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_SEPARATESTENCIL,
150 R_SHADOW_RENDERMODE_STENCILTWOSIDE,
151 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
152 R_SHADOW_RENDERMODE_LIGHT_DOT3,
153 R_SHADOW_RENDERMODE_LIGHT_GLSL,
154 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
155 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
157 r_shadow_rendermode_t;
159 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
160 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
161 r_shadow_rendermode_t r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_NONE;
163 int maxshadowtriangles;
166 int maxshadowvertices;
167 float *shadowvertex3f;
180 int r_shadow_buffer_numleafpvsbytes;
181 unsigned char *r_shadow_buffer_leafpvs;
182 int *r_shadow_buffer_leaflist;
184 int r_shadow_buffer_numsurfacepvsbytes;
185 unsigned char *r_shadow_buffer_surfacepvs;
186 int *r_shadow_buffer_surfacelist;
188 rtexturepool_t *r_shadow_texturepool;
189 rtexture_t *r_shadow_attenuation2dtexture;
190 rtexture_t *r_shadow_attenuation3dtexture;
192 // lights are reloaded when this changes
193 char r_shadow_mapname[MAX_QPATH];
195 // used only for light filters (cubemaps)
196 rtexturepool_t *r_shadow_filters_texturepool;
198 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"};
199 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"};
200 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
201 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)"};
202 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"};
203 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "2", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
204 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
205 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5", "changes attenuation texture generation (does not affect r_glsl lighting)"};
206 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1", "changes attenuation texture generation (does not affect r_glsl lighting)"};
207 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
208 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
209 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
210 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
211 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
212 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!)"};
213 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)"};
214 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"};
215 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"};
216 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
217 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
218 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"};
219 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)"};
220 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
221 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)"};
222 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)"};
223 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatetencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
224 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
225 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
226 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
227 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
228 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
229 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
230 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
232 float r_shadow_attenpower, r_shadow_attenscale;
234 rtlight_t *r_shadow_compilingrtlight;
235 dlight_t *r_shadow_worldlightchain;
236 dlight_t *r_shadow_selectedlight;
237 dlight_t r_shadow_bufferlight;
238 vec3_t r_editlights_cursorlocation;
240 extern int con_vislines;
242 typedef struct cubemapinfo_s
249 #define MAX_CUBEMAPS 256
250 static int numcubemaps;
251 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
253 void R_Shadow_UncompileWorldLights(void);
254 void R_Shadow_ClearWorldLights(void);
255 void R_Shadow_SaveWorldLights(void);
256 void R_Shadow_LoadWorldLights(void);
257 void R_Shadow_LoadLightsFile(void);
258 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
259 void R_Shadow_EditLights_Reload_f(void);
260 void R_Shadow_ValidateCvars(void);
261 static void R_Shadow_MakeTextures(void);
262 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
264 void r_shadow_start(void)
266 // allocate vertex processing arrays
268 r_shadow_attenuation2dtexture = NULL;
269 r_shadow_attenuation3dtexture = NULL;
270 r_shadow_texturepool = NULL;
271 r_shadow_filters_texturepool = NULL;
272 R_Shadow_ValidateCvars();
273 R_Shadow_MakeTextures();
274 maxshadowtriangles = 0;
275 shadowelements = NULL;
276 maxshadowvertices = 0;
277 shadowvertex3f = NULL;
285 shadowmarklist = NULL;
287 r_shadow_buffer_numleafpvsbytes = 0;
288 r_shadow_buffer_leafpvs = NULL;
289 r_shadow_buffer_leaflist = NULL;
290 r_shadow_buffer_numsurfacepvsbytes = 0;
291 r_shadow_buffer_surfacepvs = NULL;
292 r_shadow_buffer_surfacelist = NULL;
295 void r_shadow_shutdown(void)
297 R_Shadow_UncompileWorldLights();
299 r_shadow_attenuation2dtexture = NULL;
300 r_shadow_attenuation3dtexture = NULL;
301 R_FreeTexturePool(&r_shadow_texturepool);
302 R_FreeTexturePool(&r_shadow_filters_texturepool);
303 maxshadowtriangles = 0;
305 Mem_Free(shadowelements);
306 shadowelements = NULL;
308 Mem_Free(shadowvertex3f);
309 shadowvertex3f = NULL;
312 Mem_Free(vertexupdate);
315 Mem_Free(vertexremap);
321 Mem_Free(shadowmark);
324 Mem_Free(shadowmarklist);
325 shadowmarklist = NULL;
327 r_shadow_buffer_numleafpvsbytes = 0;
328 if (r_shadow_buffer_leafpvs)
329 Mem_Free(r_shadow_buffer_leafpvs);
330 r_shadow_buffer_leafpvs = NULL;
331 if (r_shadow_buffer_leaflist)
332 Mem_Free(r_shadow_buffer_leaflist);
333 r_shadow_buffer_leaflist = NULL;
334 r_shadow_buffer_numsurfacepvsbytes = 0;
335 if (r_shadow_buffer_surfacepvs)
336 Mem_Free(r_shadow_buffer_surfacepvs);
337 r_shadow_buffer_surfacepvs = NULL;
338 if (r_shadow_buffer_surfacelist)
339 Mem_Free(r_shadow_buffer_surfacelist);
340 r_shadow_buffer_surfacelist = NULL;
343 void r_shadow_newmap(void)
347 void R_Shadow_Help_f(void)
350 "Documentation on r_shadow system:\n"
352 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
353 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
354 "r_shadow_debuglight : render only this light number (-1 = all)\n"
355 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
356 "r_shadow_gloss2intensity : brightness of forced gloss\n"
357 "r_shadow_glossintensity : brightness of textured gloss\n"
358 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
359 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
360 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
361 "r_shadow_portallight : use portal visibility for static light precomputation\n"
362 "r_shadow_projectdistance : shadow volume projection distance\n"
363 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
364 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
365 "r_shadow_realtime_dlight_portalculling : work hard to reduce graphics work\n"
366 "r_shadow_realtime_world : use high quality world lighting mode\n"
367 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
368 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
369 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
370 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
371 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
372 "r_shadow_scissor : use scissor optimization\n"
373 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
374 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
375 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
376 "r_showlighting : useful for performance testing; bright = slow!\n"
377 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
379 "r_shadow_help : this help\n"
383 void R_Shadow_Init(void)
385 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
386 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
387 Cvar_RegisterVariable(&r_shadow_debuglight);
388 Cvar_RegisterVariable(&r_shadow_gloss);
389 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
390 Cvar_RegisterVariable(&r_shadow_glossintensity);
391 Cvar_RegisterVariable(&r_shadow_glossexponent);
392 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
393 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
394 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
395 Cvar_RegisterVariable(&r_shadow_portallight);
396 Cvar_RegisterVariable(&r_shadow_projectdistance);
397 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
398 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
399 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
400 Cvar_RegisterVariable(&r_shadow_realtime_world);
401 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
402 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
403 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
404 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
405 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
406 Cvar_RegisterVariable(&r_shadow_scissor);
407 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
408 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
409 Cvar_RegisterVariable(&r_shadow_texture3d);
410 Cvar_RegisterVariable(&gl_ext_separatestencil);
411 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
412 if (gamemode == GAME_TENEBRAE)
414 Cvar_SetValue("r_shadow_gloss", 2);
415 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
417 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
418 R_Shadow_EditLights_Init();
419 r_shadow_worldlightchain = NULL;
420 maxshadowtriangles = 0;
421 shadowelements = NULL;
422 maxshadowvertices = 0;
423 shadowvertex3f = NULL;
431 shadowmarklist = NULL;
433 r_shadow_buffer_numleafpvsbytes = 0;
434 r_shadow_buffer_leafpvs = NULL;
435 r_shadow_buffer_leaflist = NULL;
436 r_shadow_buffer_numsurfacepvsbytes = 0;
437 r_shadow_buffer_surfacepvs = NULL;
438 r_shadow_buffer_surfacelist = NULL;
439 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
442 matrix4x4_t matrix_attenuationxyz =
445 {0.5, 0.0, 0.0, 0.5},
446 {0.0, 0.5, 0.0, 0.5},
447 {0.0, 0.0, 0.5, 0.5},
452 matrix4x4_t matrix_attenuationz =
455 {0.0, 0.0, 0.5, 0.5},
456 {0.0, 0.0, 0.0, 0.5},
457 {0.0, 0.0, 0.0, 0.5},
462 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
464 // make sure shadowelements is big enough for this volume
465 if (maxshadowtriangles < numtriangles)
467 maxshadowtriangles = numtriangles;
469 Mem_Free(shadowelements);
470 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
472 // make sure shadowvertex3f is big enough for this volume
473 if (maxshadowvertices < numvertices)
475 maxshadowvertices = numvertices;
477 Mem_Free(shadowvertex3f);
478 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
482 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
484 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
485 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
486 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
488 if (r_shadow_buffer_leafpvs)
489 Mem_Free(r_shadow_buffer_leafpvs);
490 if (r_shadow_buffer_leaflist)
491 Mem_Free(r_shadow_buffer_leaflist);
492 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
493 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
494 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
496 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
498 if (r_shadow_buffer_surfacepvs)
499 Mem_Free(r_shadow_buffer_surfacepvs);
500 if (r_shadow_buffer_surfacelist)
501 Mem_Free(r_shadow_buffer_surfacelist);
502 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
503 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
504 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
508 void R_Shadow_PrepareShadowMark(int numtris)
510 // make sure shadowmark is big enough for this volume
511 if (maxshadowmark < numtris)
513 maxshadowmark = numtris;
515 Mem_Free(shadowmark);
517 Mem_Free(shadowmarklist);
518 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
519 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
523 // if shadowmarkcount wrapped we clear the array and adjust accordingly
524 if (shadowmarkcount == 0)
527 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
532 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)
535 int outtriangles = 0, outvertices = 0;
538 float ratio, direction[3], projectvector[3];
540 if (projectdirection)
541 VectorScale(projectdirection, projectdistance, projectvector);
543 VectorClear(projectvector);
545 if (maxvertexupdate < innumvertices)
547 maxvertexupdate = innumvertices;
549 Mem_Free(vertexupdate);
551 Mem_Free(vertexremap);
552 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
553 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
557 if (vertexupdatenum == 0)
560 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
561 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
564 for (i = 0;i < numshadowmarktris;i++)
565 shadowmark[shadowmarktris[i]] = shadowmarkcount;
567 // create the vertices
568 if (projectdirection)
570 for (i = 0;i < numshadowmarktris;i++)
572 element = inelement3i + shadowmarktris[i] * 3;
573 for (j = 0;j < 3;j++)
575 if (vertexupdate[element[j]] != vertexupdatenum)
577 vertexupdate[element[j]] = vertexupdatenum;
578 vertexremap[element[j]] = outvertices;
579 vertex = invertex3f + element[j] * 3;
580 // project one copy of the vertex according to projectvector
581 VectorCopy(vertex, outvertex3f);
582 VectorAdd(vertex, projectvector, (outvertex3f + 3));
591 for (i = 0;i < numshadowmarktris;i++)
593 element = inelement3i + shadowmarktris[i] * 3;
594 for (j = 0;j < 3;j++)
596 if (vertexupdate[element[j]] != vertexupdatenum)
598 vertexupdate[element[j]] = vertexupdatenum;
599 vertexremap[element[j]] = outvertices;
600 vertex = invertex3f + element[j] * 3;
601 // project one copy of the vertex to the sphere radius of the light
602 // (FIXME: would projecting it to the light box be better?)
603 VectorSubtract(vertex, projectorigin, direction);
604 ratio = projectdistance / VectorLength(direction);
605 VectorCopy(vertex, outvertex3f);
606 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
614 for (i = 0;i < numshadowmarktris;i++)
616 int remappedelement[3];
618 const int *neighbortriangle;
620 markindex = shadowmarktris[i] * 3;
621 element = inelement3i + markindex;
622 neighbortriangle = inneighbor3i + markindex;
623 // output the front and back triangles
624 outelement3i[0] = vertexremap[element[0]];
625 outelement3i[1] = vertexremap[element[1]];
626 outelement3i[2] = vertexremap[element[2]];
627 outelement3i[3] = vertexremap[element[2]] + 1;
628 outelement3i[4] = vertexremap[element[1]] + 1;
629 outelement3i[5] = vertexremap[element[0]] + 1;
633 // output the sides (facing outward from this triangle)
634 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
636 remappedelement[0] = vertexremap[element[0]];
637 remappedelement[1] = vertexremap[element[1]];
638 outelement3i[0] = remappedelement[1];
639 outelement3i[1] = remappedelement[0];
640 outelement3i[2] = remappedelement[0] + 1;
641 outelement3i[3] = remappedelement[1];
642 outelement3i[4] = remappedelement[0] + 1;
643 outelement3i[5] = remappedelement[1] + 1;
648 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
650 remappedelement[1] = vertexremap[element[1]];
651 remappedelement[2] = vertexremap[element[2]];
652 outelement3i[0] = remappedelement[2];
653 outelement3i[1] = remappedelement[1];
654 outelement3i[2] = remappedelement[1] + 1;
655 outelement3i[3] = remappedelement[2];
656 outelement3i[4] = remappedelement[1] + 1;
657 outelement3i[5] = remappedelement[2] + 1;
662 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
664 remappedelement[0] = vertexremap[element[0]];
665 remappedelement[2] = vertexremap[element[2]];
666 outelement3i[0] = remappedelement[0];
667 outelement3i[1] = remappedelement[2];
668 outelement3i[2] = remappedelement[2] + 1;
669 outelement3i[3] = remappedelement[0];
670 outelement3i[4] = remappedelement[2] + 1;
671 outelement3i[5] = remappedelement[0] + 1;
678 *outnumvertices = outvertices;
682 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)
685 if (projectdistance < 0.1)
687 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
690 if (!numverts || !nummarktris)
692 // make sure shadowelements is big enough for this volume
693 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
694 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
695 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
696 r_refdef.stats.lights_dynamicshadowtriangles += tris;
697 R_Shadow_RenderVolume(outverts, tris, shadowvertex3f, shadowelements);
700 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)
706 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
708 tend = firsttriangle + numtris;
709 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
710 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
711 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
713 // surface box entirely inside light box, no box cull
714 if (projectdirection)
716 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
718 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
719 if (DotProduct(normal, projectdirection) < 0)
720 shadowmarklist[numshadowmark++] = t;
725 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
726 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
727 shadowmarklist[numshadowmark++] = t;
732 // surface box not entirely inside light box, cull each triangle
733 if (projectdirection)
735 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
737 v[0] = invertex3f + e[0] * 3;
738 v[1] = invertex3f + e[1] * 3;
739 v[2] = invertex3f + e[2] * 3;
740 TriangleNormal(v[0], v[1], v[2], normal);
741 if (DotProduct(normal, projectdirection) < 0
742 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
743 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
744 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
745 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
746 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
747 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
748 shadowmarklist[numshadowmark++] = t;
753 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
755 v[0] = invertex3f + e[0] * 3;
756 v[1] = invertex3f + e[1] * 3;
757 v[2] = invertex3f + e[2] * 3;
758 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
759 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
760 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
761 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
762 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
763 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
764 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
765 shadowmarklist[numshadowmark++] = t;
771 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
773 if (r_shadow_compilingrtlight)
775 // if we're compiling an rtlight, capture the mesh
776 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
779 r_refdef.stats.lights_shadowtriangles += numtriangles;
781 R_Mesh_VertexPointer(vertex3f);
782 GL_LockArrays(0, numvertices);
783 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
785 // decrement stencil if backface is behind depthbuffer
786 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
787 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
788 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
789 // increment stencil if frontface is behind depthbuffer
790 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
791 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
793 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
798 static void R_Shadow_MakeTextures(void)
801 float v[3], intensity;
803 R_FreeTexturePool(&r_shadow_texturepool);
804 r_shadow_texturepool = R_AllocTexturePool();
805 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
806 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
807 #define ATTEN2DSIZE 64
808 #define ATTEN3DSIZE 32
809 data = (unsigned char *)Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
810 for (y = 0;y < ATTEN2DSIZE;y++)
812 for (x = 0;x < ATTEN2DSIZE;x++)
814 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
815 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
817 intensity = 1.0f - sqrt(DotProduct(v, v));
819 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
820 d = (int)bound(0, intensity, 255);
821 data[(y*ATTEN2DSIZE+x)*4+0] = d;
822 data[(y*ATTEN2DSIZE+x)*4+1] = d;
823 data[(y*ATTEN2DSIZE+x)*4+2] = d;
824 data[(y*ATTEN2DSIZE+x)*4+3] = d;
827 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
828 if (r_shadow_texture3d.integer && gl_texture3d)
830 for (z = 0;z < ATTEN3DSIZE;z++)
832 for (y = 0;y < ATTEN3DSIZE;y++)
834 for (x = 0;x < ATTEN3DSIZE;x++)
836 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
837 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
838 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
839 intensity = 1.0f - sqrt(DotProduct(v, v));
841 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
842 d = (int)bound(0, intensity, 255);
843 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
844 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
845 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
846 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
850 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
855 void R_Shadow_ValidateCvars(void)
857 if (r_shadow_texture3d.integer && !gl_texture3d)
858 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
859 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
860 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
861 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
862 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
865 // light currently being rendered
866 rtlight_t *r_shadow_rtlight;
868 // this is the location of the light in entity space
869 vec3_t r_shadow_entitylightorigin;
870 // this transforms entity coordinates to light filter cubemap coordinates
871 // (also often used for other purposes)
872 matrix4x4_t r_shadow_entitytolight;
873 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
874 // of attenuation texturing in full 3D (Z result often ignored)
875 matrix4x4_t r_shadow_entitytoattenuationxyz;
876 // this transforms only the Z to S, and T is always 0.5
877 matrix4x4_t r_shadow_entitytoattenuationz;
879 void R_Shadow_RenderMode_Begin(void)
881 R_Shadow_ValidateCvars();
883 if (!r_shadow_attenuation2dtexture
884 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
885 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
886 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
887 R_Shadow_MakeTextures();
890 R_Mesh_ColorPointer(NULL);
891 R_Mesh_ResetTextureState();
892 GL_BlendFunc(GL_ONE, GL_ZERO);
895 GL_Color(0, 0, 0, 1);
896 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
898 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
900 if (gl_ext_separatestencil.integer)
901 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
902 else if (gl_ext_stenciltwoside.integer)
903 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
905 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
907 if (r_glsl.integer && gl_support_fragment_shader)
908 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
909 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
910 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
912 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
915 void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
917 r_shadow_rtlight = rtlight;
920 void R_Shadow_RenderMode_Reset(void)
923 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
925 qglUseProgramObjectARB(0);CHECKGLERROR
927 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
929 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
931 R_Mesh_ColorPointer(NULL);
932 R_Mesh_ResetTextureState();
935 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
936 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
937 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
938 qglStencilMask(~0);CHECKGLERROR
939 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
940 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
941 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
942 GL_Color(1, 1, 1, 1);
943 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
944 GL_BlendFunc(GL_ONE, GL_ZERO);
947 void R_Shadow_RenderMode_StencilShadowVolumes(void)
950 R_Shadow_RenderMode_Reset();
951 GL_ColorMask(0, 0, 0, 0);
952 qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
953 qglDepthFunc(GL_LESS);CHECKGLERROR
954 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
955 r_shadow_rendermode = r_shadow_shadowingrendermode;
956 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SEPARATESTENCIL)
958 GL_CullFace(GL_NONE);
959 qglStencilOpSeparate(GL_BACK, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR // quake is backwards, this is front faces
960 qglStencilOpSeparate(GL_FRONT, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR // quake is backwards, this is back faces
962 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
964 GL_CullFace(GL_NONE);
965 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
966 qglActiveStencilFaceEXT(GL_BACK);CHECKGLERROR // quake is backwards, this is front faces
967 qglStencilMask(~0);CHECKGLERROR
968 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
969 qglActiveStencilFaceEXT(GL_FRONT);CHECKGLERROR // quake is backwards, this is back faces
970 qglStencilMask(~0);CHECKGLERROR
971 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
973 GL_Clear(GL_STENCIL_BUFFER_BIT);
974 r_refdef.stats.lights_clears++;
977 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
980 R_Shadow_RenderMode_Reset();
981 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
984 qglDepthFunc(GL_EQUAL);CHECKGLERROR
988 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
989 // only draw light where this geometry was already rendered AND the
990 // stencil is 128 (values other than this mean shadow)
991 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_DepthTest(r_showshadowvolumes.integer < 2);
1020 GL_Color(0.0, 0.0125 * r_view.colorscale, 0.1 * r_view.colorscale, 1);
1021 qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1022 GL_CullFace(GL_NONE);
1023 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1026 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1029 R_Shadow_RenderMode_Reset();
1030 GL_BlendFunc(GL_ONE, GL_ONE);
1031 GL_DepthTest(r_showlighting.integer < 2);
1032 GL_Color(0.1 * r_view.colorscale, 0.0125 * r_view.colorscale, 0, 1);
1035 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1039 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1041 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1044 void R_Shadow_RenderMode_End(void)
1047 R_Shadow_RenderMode_Reset();
1048 R_Shadow_RenderMode_ActiveLight(NULL);
1050 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1051 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1054 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1056 int i, ix1, iy1, ix2, iy2;
1057 float x1, y1, x2, y2;
1060 mplane_t planes[11];
1061 float vertex3f[256*3];
1063 // if view is inside the light box, just say yes it's visible
1064 if (BoxesOverlap(r_view.origin, r_view.origin, mins, maxs))
1066 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1070 // create a temporary brush describing the area the light can affect in worldspace
1071 VectorNegate(r_view.frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -r_view.frustum[0].dist;
1072 VectorNegate(r_view.frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -r_view.frustum[1].dist;
1073 VectorNegate(r_view.frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -r_view.frustum[2].dist;
1074 VectorNegate(r_view.frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -r_view.frustum[3].dist;
1075 VectorNegate(r_view.frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -r_view.frustum[4].dist;
1076 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1077 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1078 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1079 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1080 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1081 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1083 // turn the brush into a mesh
1084 memset(&mesh, 0, sizeof(rmesh_t));
1085 mesh.maxvertices = 256;
1086 mesh.vertex3f = vertex3f;
1087 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1088 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1090 // if that mesh is empty, the light is not visible at all
1091 if (!mesh.numvertices)
1094 if (!r_shadow_scissor.integer)
1097 // if that mesh is not empty, check what area of the screen it covers
1098 x1 = y1 = x2 = y2 = 0;
1100 //Con_Printf("%i vertices to transform...\n", mesh.numvertices);
1101 for (i = 0;i < mesh.numvertices;i++)
1103 VectorCopy(mesh.vertex3f + i * 3, v);
1104 GL_TransformToScreen(v, v2);
1105 //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]);
1108 if (x1 > v2[0]) x1 = v2[0];
1109 if (x2 < v2[0]) x2 = v2[0];
1110 if (y1 > v2[1]) y1 = v2[1];
1111 if (y2 < v2[1]) y2 = v2[1];
1120 // now convert the scissor rectangle to integer screen coordinates
1121 ix1 = (int)(x1 - 1.0f);
1122 iy1 = (int)(y1 - 1.0f);
1123 ix2 = (int)(x2 + 1.0f);
1124 iy2 = (int)(y2 + 1.0f);
1125 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1127 // clamp it to the screen
1128 if (ix1 < r_view.x) ix1 = r_view.x;
1129 if (iy1 < r_view.y) iy1 = r_view.y;
1130 if (ix2 > r_view.x + r_view.width) ix2 = r_view.x + r_view.width;
1131 if (iy2 > r_view.y + r_view.height) iy2 = r_view.y + r_view.height;
1133 // if it is inside out, it's not visible
1134 if (ix2 <= ix1 || iy2 <= iy1)
1137 // the light area is visible, set up the scissor rectangle
1138 GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1139 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1140 //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1141 r_refdef.stats.lights_scissored++;
1145 static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor)
1147 int numverts = surface->num_vertices;
1148 float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1149 float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1150 float *color4f = rsurface_array_color4f + 4 * surface->num_firstvertex;
1151 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1152 if (r_textureunits.integer >= 3)
1154 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1156 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1157 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1158 if ((dot = DotProduct(n, v)) < 0)
1160 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1161 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]);
1162 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]);
1163 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]);
1164 if (r_refdef.fogenabled)
1166 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1167 VectorScale(color4f, f, color4f);
1171 VectorClear(color4f);
1175 else if (r_textureunits.integer >= 2)
1177 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1179 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1180 if ((dist = fabs(v[2])) < 1)
1182 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1183 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1184 if ((dot = DotProduct(n, v)) < 0)
1186 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1187 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1188 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1189 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1193 color4f[0] = ambientcolor[0] * distintensity;
1194 color4f[1] = ambientcolor[1] * distintensity;
1195 color4f[2] = ambientcolor[2] * distintensity;
1197 if (r_refdef.fogenabled)
1199 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1200 VectorScale(color4f, f, color4f);
1204 VectorClear(color4f);
1210 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1212 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1213 if ((dist = DotProduct(v, v)) < 1)
1216 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1217 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1218 if ((dot = DotProduct(n, v)) < 0)
1220 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1221 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1222 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1223 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1227 color4f[0] = ambientcolor[0] * distintensity;
1228 color4f[1] = ambientcolor[1] * distintensity;
1229 color4f[2] = ambientcolor[2] * distintensity;
1231 if (r_refdef.fogenabled)
1233 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1234 VectorScale(color4f, f, color4f);
1238 VectorClear(color4f);
1244 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1246 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int numsurfaces, msurface_t **surfacelist)
1248 int surfacelistindex;
1249 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1251 const msurface_t *surface = surfacelist[surfacelistindex];
1253 float *out3f = rsurface_array_texcoord3f + 3 * surface->num_firstvertex;
1254 const float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1255 const float *svector3f = rsurface_svector3f + 3 * surface->num_firstvertex;
1256 const float *tvector3f = rsurface_tvector3f + 3 * surface->num_firstvertex;
1257 const float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1259 for (i = 0;i < surface->num_vertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1261 VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1262 // the cubemap normalizes this for us
1263 out3f[0] = DotProduct(svector3f, lightdir);
1264 out3f[1] = DotProduct(tvector3f, lightdir);
1265 out3f[2] = DotProduct(normal3f, lightdir);
1270 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int numsurfaces, msurface_t **surfacelist)
1272 int surfacelistindex;
1273 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1275 const msurface_t *surface = surfacelist[surfacelistindex];
1277 float *out3f = rsurface_array_texcoord3f + 3 * surface->num_firstvertex;
1278 const float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1279 const float *svector3f = rsurface_svector3f + 3 * surface->num_firstvertex;
1280 const float *tvector3f = rsurface_tvector3f + 3 * surface->num_firstvertex;
1281 const float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1282 float lightdir[3], eyedir[3], halfdir[3];
1283 for (i = 0;i < surface->num_vertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1285 VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1286 VectorNormalize(lightdir);
1287 VectorSubtract(rsurface_modelorg, vertex3f, eyedir);
1288 VectorNormalize(eyedir);
1289 VectorAdd(lightdir, eyedir, halfdir);
1290 // the cubemap normalizes this for us
1291 out3f[0] = DotProduct(svector3f, halfdir);
1292 out3f[1] = DotProduct(tvector3f, halfdir);
1293 out3f[2] = DotProduct(normal3f, halfdir);
1298 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)
1300 // used to display how many times a surface is lit for level design purposes
1301 GL_Color(0.1 * r_view.colorscale, 0.025 * r_view.colorscale, 0, 1);
1302 R_Mesh_ColorPointer(NULL);
1303 R_Mesh_ResetTextureState();
1304 RSurf_PrepareVerticesForBatch(false, false, numsurfaces, surfacelist);
1305 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1306 GL_LockArrays(0, 0);
1309 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)
1311 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1312 RSurf_PrepareVerticesForBatch(true, true, numsurfaces, surfacelist);
1313 R_SetupSurfaceShader(lightcolorbase, false);
1314 R_Mesh_TexCoordPointer(0, 2, rsurface_model->surfmesh.data_texcoordtexture2f);
1315 R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
1316 R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
1317 R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
1318 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1320 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1322 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1323 GL_LockArrays(0, 0);
1324 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1326 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1330 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(int numsurfaces, msurface_t **surfacelist, float r, float g, float b)
1332 // shared final code for all the dot3 layers
1334 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1335 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1337 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1338 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1339 GL_LockArrays(0, 0);
1343 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
1346 // colorscale accounts for how much we multiply the brightness
1349 // mult is how many times the final pass of the lighting will be
1350 // performed to get more brightness than otherwise possible.
1352 // Limit mult to 64 for sanity sake.
1354 if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1356 // 3 3D combine path (Geforce3, Radeon 8500)
1357 memset(&m, 0, sizeof(m));
1358 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1359 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1360 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1361 m.tex[1] = R_GetTexture(basetexture);
1362 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1363 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1364 m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1365 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1366 m.texmatrix[2] = r_shadow_entitytolight;
1367 GL_BlendFunc(GL_ONE, GL_ONE);
1369 else if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1371 // 2 3D combine path (Geforce3, original Radeon)
1372 memset(&m, 0, sizeof(m));
1373 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1374 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1375 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1376 m.tex[1] = R_GetTexture(basetexture);
1377 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1378 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1379 GL_BlendFunc(GL_ONE, GL_ONE);
1381 else if (r_textureunits.integer >= 4 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1383 // 4 2D combine path (Geforce3, Radeon 8500)
1384 memset(&m, 0, sizeof(m));
1385 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1386 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1387 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1388 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1389 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1390 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1391 m.tex[2] = R_GetTexture(basetexture);
1392 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1393 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1394 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1396 m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1397 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1398 m.texmatrix[3] = r_shadow_entitytolight;
1400 GL_BlendFunc(GL_ONE, GL_ONE);
1402 else if (r_textureunits.integer >= 3 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1404 // 3 2D combine path (Geforce3, original Radeon)
1405 memset(&m, 0, sizeof(m));
1406 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1407 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1408 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1409 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1410 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1411 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1412 m.tex[2] = R_GetTexture(basetexture);
1413 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1414 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1415 GL_BlendFunc(GL_ONE, GL_ONE);
1419 // 2/2/2 2D combine path (any dot3 card)
1420 memset(&m, 0, sizeof(m));
1421 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1422 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1423 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1424 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1425 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1426 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1427 R_Mesh_TextureState(&m);
1428 GL_ColorMask(0,0,0,1);
1429 GL_BlendFunc(GL_ONE, GL_ZERO);
1430 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1431 GL_LockArrays(0, 0);
1434 memset(&m, 0, sizeof(m));
1435 m.tex[0] = R_GetTexture(basetexture);
1436 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1437 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1438 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1440 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1441 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1442 m.texmatrix[1] = r_shadow_entitytolight;
1444 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1446 // this final code is shared
1447 R_Mesh_TextureState(&m);
1448 R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1451 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)
1454 // colorscale accounts for how much we multiply the brightness
1457 // mult is how many times the final pass of the lighting will be
1458 // performed to get more brightness than otherwise possible.
1460 // Limit mult to 64 for sanity sake.
1462 // generate normalization cubemap texcoords
1463 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(numsurfaces, surfacelist);
1464 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1466 // 3/2 3D combine path (Geforce3, Radeon 8500)
1467 memset(&m, 0, sizeof(m));
1468 m.tex[0] = R_GetTexture(normalmaptexture);
1469 m.texcombinergb[0] = GL_REPLACE;
1470 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1471 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1472 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1473 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1474 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1475 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1476 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1477 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1478 R_Mesh_TextureState(&m);
1479 GL_ColorMask(0,0,0,1);
1480 GL_BlendFunc(GL_ONE, GL_ZERO);
1481 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1482 GL_LockArrays(0, 0);
1485 memset(&m, 0, sizeof(m));
1486 m.tex[0] = R_GetTexture(basetexture);
1487 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1488 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1489 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1491 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1492 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1493 m.texmatrix[1] = r_shadow_entitytolight;
1495 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1497 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1499 // 1/2/2 3D combine path (original Radeon)
1500 memset(&m, 0, sizeof(m));
1501 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1502 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1503 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1504 R_Mesh_TextureState(&m);
1505 GL_ColorMask(0,0,0,1);
1506 GL_BlendFunc(GL_ONE, GL_ZERO);
1507 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1508 GL_LockArrays(0, 0);
1511 memset(&m, 0, sizeof(m));
1512 m.tex[0] = R_GetTexture(normalmaptexture);
1513 m.texcombinergb[0] = GL_REPLACE;
1514 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1515 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1516 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1517 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1518 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1519 R_Mesh_TextureState(&m);
1520 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1521 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1522 GL_LockArrays(0, 0);
1525 memset(&m, 0, sizeof(m));
1526 m.tex[0] = R_GetTexture(basetexture);
1527 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1528 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1529 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1531 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1532 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1533 m.texmatrix[1] = r_shadow_entitytolight;
1535 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1537 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1539 // 2/2 3D combine path (original Radeon)
1540 memset(&m, 0, sizeof(m));
1541 m.tex[0] = R_GetTexture(normalmaptexture);
1542 m.texcombinergb[0] = GL_REPLACE;
1543 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1544 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1545 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1546 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1547 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1548 R_Mesh_TextureState(&m);
1549 GL_ColorMask(0,0,0,1);
1550 GL_BlendFunc(GL_ONE, GL_ZERO);
1551 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1552 GL_LockArrays(0, 0);
1555 memset(&m, 0, sizeof(m));
1556 m.tex[0] = R_GetTexture(basetexture);
1557 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1558 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1559 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1560 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1561 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1562 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1564 else if (r_textureunits.integer >= 4)
1566 // 4/2 2D combine path (Geforce3, Radeon 8500)
1567 memset(&m, 0, sizeof(m));
1568 m.tex[0] = R_GetTexture(normalmaptexture);
1569 m.texcombinergb[0] = GL_REPLACE;
1570 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1571 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1572 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1573 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1574 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1575 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1576 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1577 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1578 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1579 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1580 m.texmatrix[3] = r_shadow_entitytoattenuationz;
1581 R_Mesh_TextureState(&m);
1582 GL_ColorMask(0,0,0,1);
1583 GL_BlendFunc(GL_ONE, GL_ZERO);
1584 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1585 GL_LockArrays(0, 0);
1588 memset(&m, 0, sizeof(m));
1589 m.tex[0] = R_GetTexture(basetexture);
1590 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1591 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1592 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1594 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1595 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1596 m.texmatrix[1] = r_shadow_entitytolight;
1598 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1602 // 2/2/2 2D combine path (any dot3 card)
1603 memset(&m, 0, sizeof(m));
1604 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1605 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1606 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1607 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1608 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1609 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1610 R_Mesh_TextureState(&m);
1611 GL_ColorMask(0,0,0,1);
1612 GL_BlendFunc(GL_ONE, GL_ZERO);
1613 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1614 GL_LockArrays(0, 0);
1617 memset(&m, 0, sizeof(m));
1618 m.tex[0] = R_GetTexture(normalmaptexture);
1619 m.texcombinergb[0] = GL_REPLACE;
1620 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1621 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1622 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1623 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1624 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1625 R_Mesh_TextureState(&m);
1626 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1627 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1628 GL_LockArrays(0, 0);
1631 memset(&m, 0, sizeof(m));
1632 m.tex[0] = R_GetTexture(basetexture);
1633 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1634 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1635 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1637 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1638 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1639 m.texmatrix[1] = r_shadow_entitytolight;
1641 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1643 // this final code is shared
1644 R_Mesh_TextureState(&m);
1645 R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1648 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)
1650 float glossexponent;
1652 // FIXME: detect blendsquare!
1653 //if (!gl_support_blendsquare)
1656 // generate normalization cubemap texcoords
1657 R_Shadow_GenTexCoords_Specular_NormalCubeMap(numsurfaces, surfacelist);
1658 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1660 // 2/0/0/1/2 3D combine blendsquare path
1661 memset(&m, 0, sizeof(m));
1662 m.tex[0] = R_GetTexture(normalmaptexture);
1663 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1664 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1665 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1666 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1667 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1668 R_Mesh_TextureState(&m);
1669 GL_ColorMask(0,0,0,1);
1670 // this squares the result
1671 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1672 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1673 GL_LockArrays(0, 0);
1675 // second and third pass
1676 R_Mesh_ResetTextureState();
1677 // square alpha in framebuffer a few times to make it shiny
1678 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1679 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1680 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1681 GL_LockArrays(0, 0);
1684 memset(&m, 0, sizeof(m));
1685 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1686 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1687 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1688 R_Mesh_TextureState(&m);
1689 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1690 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1691 GL_LockArrays(0, 0);
1694 memset(&m, 0, sizeof(m));
1695 m.tex[0] = R_GetTexture(glosstexture);
1696 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1697 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1698 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1700 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1701 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1702 m.texmatrix[1] = r_shadow_entitytolight;
1704 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1706 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1708 // 2/0/0/2 3D combine blendsquare path
1709 memset(&m, 0, sizeof(m));
1710 m.tex[0] = R_GetTexture(normalmaptexture);
1711 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1712 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1713 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1714 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1715 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1716 R_Mesh_TextureState(&m);
1717 GL_ColorMask(0,0,0,1);
1718 // this squares the result
1719 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1720 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1721 GL_LockArrays(0, 0);
1723 // second and third pass
1724 R_Mesh_ResetTextureState();
1725 // square alpha in framebuffer a few times to make it shiny
1726 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1727 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
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 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1737 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1738 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1739 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1743 // 2/0/0/2/2 2D combine blendsquare path
1744 memset(&m, 0, sizeof(m));
1745 m.tex[0] = R_GetTexture(normalmaptexture);
1746 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1747 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1748 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1749 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1750 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1751 R_Mesh_TextureState(&m);
1752 GL_ColorMask(0,0,0,1);
1753 // this squares the result
1754 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1755 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1756 GL_LockArrays(0, 0);
1758 // second and third pass
1759 R_Mesh_ResetTextureState();
1760 // square alpha in framebuffer a few times to make it shiny
1761 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1762 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1763 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1764 GL_LockArrays(0, 0);
1767 memset(&m, 0, sizeof(m));
1768 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1769 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1770 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1771 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1772 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1773 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1774 R_Mesh_TextureState(&m);
1775 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1776 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1777 GL_LockArrays(0, 0);
1780 memset(&m, 0, sizeof(m));
1781 m.tex[0] = R_GetTexture(glosstexture);
1782 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1783 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1784 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1786 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1787 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1788 m.texmatrix[1] = r_shadow_entitytolight;
1790 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1792 // this final code is shared
1793 R_Mesh_TextureState(&m);
1794 R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1797 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)
1799 // ARB path (any Geforce, any Radeon)
1800 qboolean doambient = r_shadow_rtlight->ambientscale > 0;
1801 qboolean dodiffuse = r_shadow_rtlight->diffusescale > 0;
1802 qboolean dospecular = specularscale > 0;
1803 if (!doambient && !dodiffuse && !dospecular)
1805 RSurf_PrepareVerticesForBatch(true, true, numsurfaces, surfacelist);
1806 R_Mesh_ColorPointer(NULL);
1808 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorbase, basetexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1810 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorbase, basetexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1814 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorpants, pantstexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1816 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorpants, pantstexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1821 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1823 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1826 R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(numsurfaces, surfacelist, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale);
1829 void R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(const model_t *model, int numsurfaces, msurface_t **surfacelist, vec3_t diffusecolor2, vec3_t ambientcolor2)
1831 int surfacelistindex;
1833 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1835 const msurface_t *surface = surfacelist[surfacelistindex];
1836 R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(surface, diffusecolor2, ambientcolor2);
1838 for (renders = 0;renders < 64;renders++)
1844 int newnumtriangles;
1846 int newelements[3072];
1850 newnumtriangles = 0;
1852 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1854 const msurface_t *surface = surfacelist[surfacelistindex];
1855 const int *elements = rsurface_model->surfmesh.data_element3i + surface->num_firsttriangle * 3;
1857 // due to low fillrate on the cards this vertex lighting path is
1858 // designed for, we manually cull all triangles that do not
1859 // contain a lit vertex
1860 // this builds batches of triangles from multiple surfaces and
1861 // renders them at once
1862 for (i = 0, e = elements;i < surface->num_triangles;i++, e += 3)
1864 if (VectorLength2(rsurface_array_color4f + e[0] * 4) + VectorLength2(rsurface_array_color4f + e[1] * 4) + VectorLength2(rsurface_array_color4f + e[2] * 4) >= 0.01)
1866 if (newnumtriangles)
1868 firstvertex = min(firstvertex, e[0]);
1869 lastvertex = max(lastvertex, e[0]);
1876 firstvertex = min(firstvertex, e[1]);
1877 lastvertex = max(lastvertex, e[1]);
1878 firstvertex = min(firstvertex, e[2]);
1879 lastvertex = max(lastvertex, e[2]);
1885 if (newnumtriangles >= 1024)
1887 GL_LockArrays(firstvertex, lastvertex - firstvertex + 1);
1888 R_Mesh_Draw(firstvertex, lastvertex - firstvertex + 1, newnumtriangles, newelements);
1889 newnumtriangles = 0;
1896 if (newnumtriangles >= 1)
1898 GL_LockArrays(firstvertex, lastvertex - firstvertex + 1);
1899 R_Mesh_Draw(firstvertex, lastvertex - firstvertex + 1, newnumtriangles, newelements);
1902 GL_LockArrays(0, 0);
1903 // if we couldn't find any lit triangles, exit early
1906 // now reduce the intensity for the next overbright pass
1907 // we have to clamp to 0 here incase the drivers have improper
1908 // handling of negative colors
1909 // (some old drivers even have improper handling of >1 color)
1911 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1915 const msurface_t *surface = surfacelist[surfacelistindex];
1916 for (i = 0, c = rsurface_array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
1918 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
1920 c[0] = max(0, c[0] - 1);
1921 c[1] = max(0, c[1] - 1);
1922 c[2] = max(0, c[2] - 1);
1935 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)
1937 // OpenGL 1.1 path (anything)
1938 model_t *model = rsurface_entity->model;
1939 float ambientcolorbase[3], diffusecolorbase[3];
1940 float ambientcolorpants[3], diffusecolorpants[3];
1941 float ambientcolorshirt[3], diffusecolorshirt[3];
1943 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorbase);
1944 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorbase);
1945 VectorScale(lightcolorpants, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorpants);
1946 VectorScale(lightcolorpants, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorpants);
1947 VectorScale(lightcolorshirt, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorshirt);
1948 VectorScale(lightcolorshirt, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorshirt);
1949 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1950 R_Mesh_ColorPointer(rsurface_array_color4f);
1951 memset(&m, 0, sizeof(m));
1952 m.tex[0] = R_GetTexture(basetexture);
1953 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1954 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1955 if (r_textureunits.integer >= 2)
1958 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1959 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1960 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1961 if (r_textureunits.integer >= 3)
1963 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
1964 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1965 m.texmatrix[2] = r_shadow_entitytoattenuationz;
1966 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1969 R_Mesh_TextureState(&m);
1970 RSurf_PrepareVerticesForBatch(true, false, numsurfaces, surfacelist);
1971 R_Mesh_TexBind(0, R_GetTexture(basetexture));
1972 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorbase, ambientcolorbase);
1975 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
1976 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorpants, ambientcolorpants);
1980 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
1981 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorshirt, ambientcolorshirt);
1985 void R_Shadow_RenderSurfacesLighting(int numsurfaces, msurface_t **surfacelist)
1987 // FIXME: support MATERIALFLAG_NODEPTHTEST
1988 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
1989 // calculate colors to render this texture with
1990 lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * rsurface_entity->colormod[0] * rsurface_texture->currentalpha;
1991 lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * rsurface_entity->colormod[1] * rsurface_texture->currentalpha;
1992 lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * rsurface_entity->colormod[2] * rsurface_texture->currentalpha;
1993 if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) + (r_shadow_rtlight->specularscale * rsurface_texture->specularscale) * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
1995 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
1996 GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
1997 if (rsurface_texture->colormapping)
1999 qboolean dopants = rsurface_texture->currentskinframe->pants != NULL && VectorLength2(rsurface_entity->colormap_pantscolor) >= (1.0f / 1048576.0f);
2000 qboolean doshirt = rsurface_texture->currentskinframe->shirt != NULL && VectorLength2(rsurface_entity->colormap_shirtcolor) >= (1.0f / 1048576.0f);
2003 lightcolorpants[0] = lightcolorbase[0] * rsurface_entity->colormap_pantscolor[0];
2004 lightcolorpants[1] = lightcolorbase[1] * rsurface_entity->colormap_pantscolor[1];
2005 lightcolorpants[2] = lightcolorbase[2] * rsurface_entity->colormap_pantscolor[2];
2008 VectorClear(lightcolorpants);
2011 lightcolorshirt[0] = lightcolorbase[0] * rsurface_entity->colormap_shirtcolor[0];
2012 lightcolorshirt[1] = lightcolorbase[1] * rsurface_entity->colormap_shirtcolor[1];
2013 lightcolorshirt[2] = lightcolorbase[2] * rsurface_entity->colormap_shirtcolor[2];
2016 VectorClear(lightcolorshirt);
2017 switch (r_shadow_rendermode)
2019 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2020 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2021 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);
2023 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2024 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);
2026 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2027 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);
2029 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2030 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);
2033 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2039 switch (r_shadow_rendermode)
2041 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2042 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2043 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);
2045 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2046 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);
2048 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2049 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);
2051 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2052 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);
2055 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2061 void R_RTLight_Update(dlight_t *light, int isstatic)
2064 rtlight_t *rtlight = &light->rtlight;
2065 R_RTLight_Uncompile(rtlight);
2066 memset(rtlight, 0, sizeof(*rtlight));
2068 VectorCopy(light->origin, rtlight->shadoworigin);
2069 VectorCopy(light->color, rtlight->color);
2070 rtlight->radius = light->radius;
2071 //rtlight->cullradius = rtlight->radius;
2072 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2073 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2074 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2075 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2076 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2077 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2078 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2079 rtlight->cubemapname[0] = 0;
2080 if (light->cubemapname[0])
2081 strlcpy(rtlight->cubemapname, light->cubemapname, sizeof(rtlight->cubemapname));
2082 else if (light->cubemapnum > 0)
2083 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2084 rtlight->shadow = light->shadow;
2085 rtlight->corona = light->corona;
2086 rtlight->style = light->style;
2087 rtlight->isstatic = isstatic;
2088 rtlight->coronasizescale = light->coronasizescale;
2089 rtlight->ambientscale = light->ambientscale;
2090 rtlight->diffusescale = light->diffusescale;
2091 rtlight->specularscale = light->specularscale;
2092 rtlight->flags = light->flags;
2093 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2094 // this has to scale both rotate and translate because this is an already
2095 // inverted matrix (it transforms from world to light space, not the other
2097 scale = 1.0 / rtlight->radius;
2098 Matrix4x4_Scale(&rtlight->matrix_worldtolight, scale, scale);
2101 // compiles rtlight geometry
2102 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2103 void R_RTLight_Compile(rtlight_t *rtlight)
2105 int shadowmeshes, shadowtris, numleafs, numleafpvsbytes, numsurfaces;
2106 entity_render_t *ent = r_refdef.worldentity;
2107 model_t *model = r_refdef.worldmodel;
2108 unsigned char *data;
2110 // compile the light
2111 rtlight->compiled = true;
2112 rtlight->static_numleafs = 0;
2113 rtlight->static_numleafpvsbytes = 0;
2114 rtlight->static_leaflist = NULL;
2115 rtlight->static_leafpvs = NULL;
2116 rtlight->static_numsurfaces = 0;
2117 rtlight->static_surfacelist = NULL;
2118 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2119 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2120 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2121 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2122 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2123 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2125 if (model && model->GetLightInfo)
2127 // this variable must be set for the CompileShadowVolume code
2128 r_shadow_compilingrtlight = rtlight;
2129 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
2130 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);
2131 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2132 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2133 rtlight->static_numleafs = numleafs;
2134 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2135 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2136 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2137 rtlight->static_numsurfaces = numsurfaces;
2138 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2140 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2141 if (numleafpvsbytes)
2142 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2144 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2145 if (model->CompileShadowVolume && rtlight->shadow)
2146 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2147 // now we're done compiling the rtlight
2148 r_shadow_compilingrtlight = NULL;
2152 // use smallest available cullradius - box radius or light radius
2153 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2154 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2158 if (rtlight->static_meshchain_shadow)
2161 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2164 shadowtris += mesh->numtriangles;
2168 if (developer.integer >= 10)
2169 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);
2172 void R_RTLight_Uncompile(rtlight_t *rtlight)
2174 if (rtlight->compiled)
2176 if (rtlight->static_meshchain_shadow)
2177 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2178 rtlight->static_meshchain_shadow = NULL;
2179 // these allocations are grouped
2180 if (rtlight->static_leaflist)
2181 Mem_Free(rtlight->static_leaflist);
2182 rtlight->static_numleafs = 0;
2183 rtlight->static_numleafpvsbytes = 0;
2184 rtlight->static_leaflist = NULL;
2185 rtlight->static_leafpvs = NULL;
2186 rtlight->static_numsurfaces = 0;
2187 rtlight->static_surfacelist = NULL;
2188 rtlight->compiled = false;
2192 void R_Shadow_UncompileWorldLights(void)
2195 for (light = r_shadow_worldlightchain;light;light = light->next)
2196 R_RTLight_Uncompile(&light->rtlight);
2199 void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfacelist)
2201 model_t *model = ent->model;
2202 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2203 vec_t relativeshadowradius;
2204 if (ent == r_refdef.worldentity)
2206 if (r_shadow_rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2209 R_Mesh_Matrix(&ent->matrix);
2211 for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2213 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2214 R_Mesh_VertexPointer(mesh->vertex3f);
2215 GL_LockArrays(0, mesh->numverts);
2216 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2218 // decrement stencil if backface is behind depthbuffer
2219 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
2220 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2221 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2222 // increment stencil if frontface is behind depthbuffer
2223 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2224 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2226 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2227 GL_LockArrays(0, 0);
2231 else if (numsurfaces)
2233 R_Mesh_Matrix(&ent->matrix);
2234 model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, NULL, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight->cullmins, r_shadow_rtlight->cullmaxs);
2239 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, relativeshadoworigin);
2240 relativeshadowradius = r_shadow_rtlight->radius / ent->scale;
2241 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2242 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2243 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2244 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2245 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2246 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2247 R_Mesh_Matrix(&ent->matrix);
2248 model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, model->nummodelsurfaces, model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2252 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2254 // set up properties for rendering light onto this entity
2255 RSurf_ActiveEntity(ent, true, true);
2256 Matrix4x4_Concat(&r_shadow_entitytolight, &r_shadow_rtlight->matrix_worldtolight, &ent->matrix);
2257 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2258 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2259 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2260 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2261 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2264 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2266 model_t *model = ent->model;
2267 if (!model->DrawLight)
2269 R_Shadow_SetupEntityLight(ent);
2270 if (ent == r_refdef.worldentity)
2271 model->DrawLight(ent, numsurfaces, surfacelist);
2273 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist);
2276 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2280 int numleafs, numsurfaces;
2281 int *leaflist, *surfacelist;
2282 unsigned char *leafpvs;
2283 int numlightentities;
2284 int numshadowentities;
2285 entity_render_t *lightentities[MAX_EDICTS];
2286 entity_render_t *shadowentities[MAX_EDICTS];
2288 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2289 // skip lights that are basically invisible (color 0 0 0)
2290 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2293 // loading is done before visibility checks because loading should happen
2294 // all at once at the start of a level, not when it stalls gameplay.
2295 // (especially important to benchmarks)
2297 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2298 R_RTLight_Compile(rtlight);
2300 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2302 // look up the light style value at this time
2303 f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2304 VectorScale(rtlight->color, f, rtlight->currentcolor);
2306 if (rtlight->selected)
2308 f = 2 + sin(realtime * M_PI * 4.0);
2309 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2313 // if lightstyle is currently off, don't draw the light
2314 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2317 // if the light box is offscreen, skip it
2318 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2321 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2323 // compiled light, world available and can receive realtime lighting
2324 // retrieve leaf information
2325 numleafs = rtlight->static_numleafs;
2326 leaflist = rtlight->static_leaflist;
2327 leafpvs = rtlight->static_leafpvs;
2328 numsurfaces = rtlight->static_numsurfaces;
2329 surfacelist = rtlight->static_surfacelist;
2331 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2333 // dynamic light, world available and can receive realtime lighting
2334 // calculate lit surfaces and leafs
2335 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces);
2336 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);
2337 leaflist = r_shadow_buffer_leaflist;
2338 leafpvs = r_shadow_buffer_leafpvs;
2339 surfacelist = r_shadow_buffer_surfacelist;
2340 // if the reduced leaf bounds are offscreen, skip it
2341 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2353 // check if light is illuminating any visible leafs
2356 for (i = 0;i < numleafs;i++)
2357 if (r_viewcache.world_leafvisible[leaflist[i]])
2362 // set up a scissor rectangle for this light
2363 if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
2366 // make a list of lit entities and shadow casting entities
2367 numlightentities = 0;
2368 numshadowentities = 0;
2369 // don't count the world unless some surfaces are actually lit
2372 lightentities[numlightentities++] = r_refdef.worldentity;
2373 shadowentities[numshadowentities++] = r_refdef.worldentity;
2375 // add dynamic entities that are lit by the light
2376 if (r_drawentities.integer)
2378 for (i = 0;i < r_refdef.numentities;i++)
2381 entity_render_t *ent = r_refdef.entities[i];
2382 if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
2383 && (model = ent->model)
2384 && !(ent->flags & RENDER_TRANSPARENT)
2385 && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2387 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2389 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2390 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2391 shadowentities[numshadowentities++] = ent;
2392 if (r_viewcache.entityvisible[i] && (ent->flags & RENDER_LIGHT) && model->DrawLight)
2393 lightentities[numlightentities++] = ent;
2398 // return if there's nothing at all to light
2399 if (!numlightentities)
2402 // don't let sound skip if going slow
2403 if (r_refdef.extraupdate)
2406 // make this the active rtlight for rendering purposes
2407 R_Shadow_RenderMode_ActiveLight(rtlight);
2408 // count this light in the r_speeds
2409 r_refdef.stats.lights++;
2412 if (numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2414 // draw stencil shadow volumes to mask off pixels that are in shadow
2415 // so that they won't receive lighting
2419 R_Shadow_RenderMode_StencilShadowVolumes();
2420 for (i = 0;i < numshadowentities;i++)
2421 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2424 // optionally draw visible shape of the shadow volumes
2425 // for performance analysis by level designers
2426 if (r_showshadowvolumes.integer)
2428 R_Shadow_RenderMode_VisibleShadowVolumes();
2429 for (i = 0;i < numshadowentities;i++)
2430 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2434 if (numlightentities)
2436 // draw lighting in the unmasked areas
2437 R_Shadow_RenderMode_Lighting(usestencil, false);
2438 for (i = 0;i < numlightentities;i++)
2439 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2441 // optionally draw the illuminated areas
2442 // for performance analysis by level designers
2443 if (r_showlighting.integer)
2445 R_Shadow_RenderMode_VisibleLighting(usestencil && !r_showdisabledepthtest.integer, false);
2446 for (i = 0;i < numlightentities;i++)
2447 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2452 void R_ShadowVolumeLighting(qboolean visible)
2457 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2458 R_Shadow_EditLights_Reload_f();
2460 R_Shadow_RenderMode_Begin();
2462 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2463 if (r_shadow_debuglight.integer >= 0)
2465 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2466 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2467 R_DrawRTLight(&light->rtlight, visible);
2470 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2471 if (light->flags & flag)
2472 R_DrawRTLight(&light->rtlight, visible);
2473 if (r_refdef.rtdlight)
2474 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
2475 R_DrawRTLight(&r_refdef.lights[lnum]->rtlight, visible);
2477 R_Shadow_RenderMode_End();
2480 extern void R_SetupView(const matrix4x4_t *matrix);
2481 extern cvar_t r_shadows_throwdistance;
2482 void R_DrawModelShadows(void)
2485 float relativethrowdistance;
2486 entity_render_t *ent;
2487 vec3_t relativelightorigin;
2488 vec3_t relativelightdirection;
2489 vec3_t relativeshadowmins, relativeshadowmaxs;
2492 if (!r_drawentities.integer || !gl_stencil)
2496 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2498 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2500 if (gl_ext_separatestencil.integer)
2501 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
2502 else if (gl_ext_stenciltwoside.integer)
2503 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
2505 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
2507 R_Shadow_RenderMode_StencilShadowVolumes();
2509 for (i = 0;i < r_refdef.numentities;i++)
2511 ent = r_refdef.entities[i];
2512 // cast shadows from anything that is not a submodel of the map
2513 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
2515 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
2516 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
2517 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
2518 VectorNegate(ent->modellight_lightdir, relativelightdirection);
2519 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
2520 R_Mesh_Matrix(&ent->matrix);
2521 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2525 // not really the right mode, but this will disable any silly stencil features
2526 R_Shadow_RenderMode_VisibleLighting(true, true);
2528 // vertex coordinates for a quad that covers the screen exactly
2529 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
2530 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
2531 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
2532 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
2534 // set up ortho view for rendering this pass
2535 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
2536 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2537 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2538 GL_ScissorTest(true);
2539 R_Mesh_Matrix(&identitymatrix);
2540 R_Mesh_ResetTextureState();
2541 R_Mesh_VertexPointer(vertex3f);
2542 R_Mesh_ColorPointer(NULL);
2544 // set up a 50% darkening blend on shadowed areas
2545 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2546 GL_DepthTest(false);
2547 GL_DepthMask(false);
2548 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2549 GL_Color(0, 0, 0, 0.5);
2550 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2551 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
2552 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2553 qglStencilMask(~0);CHECKGLERROR
2554 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
2555 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
2557 // apply the blend to the shadowed areas
2558 R_Mesh_Draw(0, 4, 2, polygonelements);
2560 // restoring the perspective view is done by R_RenderScene
2561 //R_SetupView(&r_view.matrix);
2563 // restore other state to normal
2564 R_Shadow_RenderMode_End();
2568 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2569 typedef struct suffixinfo_s
2572 qboolean flipx, flipy, flipdiagonal;
2575 static suffixinfo_t suffix[3][6] =
2578 {"px", false, false, false},
2579 {"nx", false, false, false},
2580 {"py", false, false, false},
2581 {"ny", false, false, false},
2582 {"pz", false, false, false},
2583 {"nz", false, false, false}
2586 {"posx", false, false, false},
2587 {"negx", false, false, false},
2588 {"posy", false, false, false},
2589 {"negy", false, false, false},
2590 {"posz", false, false, false},
2591 {"negz", false, false, false}
2594 {"rt", true, false, true},
2595 {"lf", false, true, true},
2596 {"ft", true, true, false},
2597 {"bk", false, false, false},
2598 {"up", true, false, true},
2599 {"dn", true, false, true}
2603 static int componentorder[4] = {0, 1, 2, 3};
2605 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2607 int i, j, cubemapsize;
2608 unsigned char *cubemappixels, *image_rgba;
2609 rtexture_t *cubemaptexture;
2611 // must start 0 so the first loadimagepixels has no requested width/height
2613 cubemappixels = NULL;
2614 cubemaptexture = NULL;
2615 // keep trying different suffix groups (posx, px, rt) until one loads
2616 for (j = 0;j < 3 && !cubemappixels;j++)
2618 // load the 6 images in the suffix group
2619 for (i = 0;i < 6;i++)
2621 // generate an image name based on the base and and suffix
2622 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2624 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2626 // an image loaded, make sure width and height are equal
2627 if (image_width == image_height)
2629 // if this is the first image to load successfully, allocate the cubemap memory
2630 if (!cubemappixels && image_width >= 1)
2632 cubemapsize = image_width;
2633 // note this clears to black, so unavailable sides are black
2634 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2636 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2638 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);
2641 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2643 Mem_Free(image_rgba);
2647 // if a cubemap loaded, upload it
2650 if (!r_shadow_filters_texturepool)
2651 r_shadow_filters_texturepool = R_AllocTexturePool();
2652 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2653 Mem_Free(cubemappixels);
2657 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2658 for (j = 0;j < 3;j++)
2659 for (i = 0;i < 6;i++)
2660 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2661 Con_Print(" and was unable to find any of them.\n");
2663 return cubemaptexture;
2666 rtexture_t *R_Shadow_Cubemap(const char *basename)
2669 for (i = 0;i < numcubemaps;i++)
2670 if (!strcasecmp(cubemaps[i].basename, basename))
2671 return cubemaps[i].texture;
2672 if (i >= MAX_CUBEMAPS)
2673 return r_texture_whitecube;
2675 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
2676 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2677 if (!cubemaps[i].texture)
2678 cubemaps[i].texture = r_texture_whitecube;
2679 return cubemaps[i].texture;
2682 void R_Shadow_FreeCubemaps(void)
2685 R_FreeTexturePool(&r_shadow_filters_texturepool);
2688 dlight_t *R_Shadow_NewWorldLight(void)
2691 light = (dlight_t *)Mem_Alloc(r_main_mempool, sizeof(dlight_t));
2692 light->next = r_shadow_worldlightchain;
2693 r_shadow_worldlightchain = light;
2697 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)
2699 VectorCopy(origin, light->origin);
2700 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
2701 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
2702 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
2703 light->color[0] = max(color[0], 0);
2704 light->color[1] = max(color[1], 0);
2705 light->color[2] = max(color[2], 0);
2706 light->radius = max(radius, 0);
2707 light->style = style;
2708 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2710 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2713 light->shadow = shadowenable;
2714 light->corona = corona;
2717 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
2718 light->coronasizescale = coronasizescale;
2719 light->ambientscale = ambientscale;
2720 light->diffusescale = diffusescale;
2721 light->specularscale = specularscale;
2722 light->flags = flags;
2723 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2725 R_RTLight_Update(light, true);
2728 void R_Shadow_FreeWorldLight(dlight_t *light)
2730 dlight_t **lightpointer;
2731 R_RTLight_Uncompile(&light->rtlight);
2732 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2733 if (*lightpointer != light)
2734 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
2735 *lightpointer = light->next;
2739 void R_Shadow_ClearWorldLights(void)
2741 while (r_shadow_worldlightchain)
2742 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2743 r_shadow_selectedlight = NULL;
2744 R_Shadow_FreeCubemaps();
2747 void R_Shadow_SelectLight(dlight_t *light)
2749 if (r_shadow_selectedlight)
2750 r_shadow_selectedlight->selected = false;
2751 r_shadow_selectedlight = light;
2752 if (r_shadow_selectedlight)
2753 r_shadow_selectedlight->selected = true;
2756 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2758 // this is never batched (there can be only one)
2759 float scale = r_editlights_cursorgrid.value * 0.5f;
2760 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);
2763 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2765 // this is never batched (due to the ent parameter changing every time)
2766 // so numsurfaces == 1 and surfacelist[0] == lightnumber
2768 const dlight_t *light = (dlight_t *)ent;
2770 if (light->selected)
2771 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2774 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);
2777 void R_Shadow_DrawLightSprites(void)
2782 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
2783 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 1+(i % 5), &light->rtlight);
2784 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
2787 void R_Shadow_SelectLightInView(void)
2789 float bestrating, rating, temp[3];
2790 dlight_t *best, *light;
2793 for (light = r_shadow_worldlightchain;light;light = light->next)
2795 VectorSubtract(light->origin, r_view.origin, temp);
2796 rating = (DotProduct(temp, r_view.forward) / sqrt(DotProduct(temp, temp)));
2799 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2800 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_view.origin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
2802 bestrating = rating;
2807 R_Shadow_SelectLight(best);
2810 void R_Shadow_LoadWorldLights(void)
2812 int n, a, style, shadow, flags;
2813 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
2814 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
2815 if (r_refdef.worldmodel == NULL)
2817 Con_Print("No map loaded.\n");
2820 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2821 strlcat (name, ".rtlights", sizeof (name));
2822 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
2832 for (;COM_Parse(t, true) && strcmp(
2833 if (COM_Parse(t, true))
2835 if (com_token[0] == '!')
2838 origin[0] = atof(com_token+1);
2841 origin[0] = atof(com_token);
2846 while (*s && *s != '\n' && *s != '\r')
2852 // check for modifier flags
2859 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);
2862 flags = LIGHTFLAG_REALTIMEMODE;
2870 coronasizescale = 0.25f;
2872 VectorClear(angles);
2875 if (a < 9 || !strcmp(cubemapname, "\"\""))
2877 // remove quotes on cubemapname
2878 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
2881 namelen = strlen(cubemapname) - 2;
2882 memmove(cubemapname, cubemapname + 1, namelen);
2883 cubemapname[namelen] = '\0';
2887 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);
2890 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
2898 Con_Printf("invalid rtlights file \"%s\"\n", name);
2899 Mem_Free(lightsstring);
2903 void R_Shadow_SaveWorldLights(void)
2906 size_t bufchars, bufmaxchars;
2908 char name[MAX_QPATH];
2909 char line[MAX_INPUTLINE];
2910 if (!r_shadow_worldlightchain)
2912 if (r_refdef.worldmodel == NULL)
2914 Con_Print("No map loaded.\n");
2917 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2918 strlcat (name, ".rtlights", sizeof (name));
2919 bufchars = bufmaxchars = 0;
2921 for (light = r_shadow_worldlightchain;light;light = light->next)
2923 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
2924 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);
2925 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
2926 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]);
2928 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);
2929 if (bufchars + strlen(line) > bufmaxchars)
2931 bufmaxchars = bufchars + strlen(line) + 2048;
2933 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
2937 memcpy(buf, oldbuf, bufchars);
2943 memcpy(buf + bufchars, line, strlen(line));
2944 bufchars += strlen(line);
2948 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
2953 void R_Shadow_LoadLightsFile(void)
2956 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
2957 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2958 if (r_refdef.worldmodel == NULL)
2960 Con_Print("No map loaded.\n");
2963 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2964 strlcat (name, ".lights", sizeof (name));
2965 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
2973 while (*s && *s != '\n' && *s != '\r')
2979 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);
2983 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);
2986 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2987 radius = bound(15, radius, 4096);
2988 VectorScale(color, (2.0f / (8388608.0f)), color);
2989 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
2997 Con_Printf("invalid lights file \"%s\"\n", name);
2998 Mem_Free(lightsstring);
3002 // tyrlite/hmap2 light types in the delay field
3003 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3005 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3007 int entnum, style, islight, skin, pflags, effects, type, n;
3010 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3011 char key[256], value[MAX_INPUTLINE];
3013 if (r_refdef.worldmodel == NULL)
3015 Con_Print("No map loaded.\n");
3018 // try to load a .ent file first
3019 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3020 strlcat (key, ".ent", sizeof (key));
3021 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3022 // and if that is not found, fall back to the bsp file entity string
3024 data = r_refdef.worldmodel->brush.entities;
3027 for (entnum = 0;COM_ParseTokenConsole(&data) && com_token[0] == '{';entnum++)
3029 type = LIGHTTYPE_MINUSX;
3030 origin[0] = origin[1] = origin[2] = 0;
3031 originhack[0] = originhack[1] = originhack[2] = 0;
3032 angles[0] = angles[1] = angles[2] = 0;
3033 color[0] = color[1] = color[2] = 1;
3034 light[0] = light[1] = light[2] = 1;light[3] = 300;
3035 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3045 if (!COM_ParseTokenConsole(&data))
3047 if (com_token[0] == '}')
3048 break; // end of entity
3049 if (com_token[0] == '_')
3050 strlcpy(key, com_token + 1, sizeof(key));
3052 strlcpy(key, com_token, sizeof(key));
3053 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3054 key[strlen(key)-1] = 0;
3055 if (!COM_ParseTokenConsole(&data))
3057 strlcpy(value, com_token, sizeof(value));
3059 // now that we have the key pair worked out...
3060 if (!strcmp("light", key))
3062 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3066 light[0] = vec[0] * (1.0f / 256.0f);
3067 light[1] = vec[0] * (1.0f / 256.0f);
3068 light[2] = vec[0] * (1.0f / 256.0f);
3074 light[0] = vec[0] * (1.0f / 255.0f);
3075 light[1] = vec[1] * (1.0f / 255.0f);
3076 light[2] = vec[2] * (1.0f / 255.0f);
3080 else if (!strcmp("delay", key))
3082 else if (!strcmp("origin", key))
3083 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3084 else if (!strcmp("angle", key))
3085 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3086 else if (!strcmp("angles", key))
3087 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3088 else if (!strcmp("color", key))
3089 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3090 else if (!strcmp("wait", key))
3091 fadescale = atof(value);
3092 else if (!strcmp("classname", key))
3094 if (!strncmp(value, "light", 5))
3097 if (!strcmp(value, "light_fluoro"))
3102 overridecolor[0] = 1;
3103 overridecolor[1] = 1;
3104 overridecolor[2] = 1;
3106 if (!strcmp(value, "light_fluorospark"))
3111 overridecolor[0] = 1;
3112 overridecolor[1] = 1;
3113 overridecolor[2] = 1;
3115 if (!strcmp(value, "light_globe"))
3120 overridecolor[0] = 1;
3121 overridecolor[1] = 0.8;
3122 overridecolor[2] = 0.4;
3124 if (!strcmp(value, "light_flame_large_yellow"))
3129 overridecolor[0] = 1;
3130 overridecolor[1] = 0.5;
3131 overridecolor[2] = 0.1;
3133 if (!strcmp(value, "light_flame_small_yellow"))
3138 overridecolor[0] = 1;
3139 overridecolor[1] = 0.5;
3140 overridecolor[2] = 0.1;
3142 if (!strcmp(value, "light_torch_small_white"))
3147 overridecolor[0] = 1;
3148 overridecolor[1] = 0.5;
3149 overridecolor[2] = 0.1;
3151 if (!strcmp(value, "light_torch_small_walltorch"))
3156 overridecolor[0] = 1;
3157 overridecolor[1] = 0.5;
3158 overridecolor[2] = 0.1;
3162 else if (!strcmp("style", key))
3163 style = atoi(value);
3164 else if (!strcmp("skin", key))
3165 skin = (int)atof(value);
3166 else if (!strcmp("pflags", key))
3167 pflags = (int)atof(value);
3168 else if (!strcmp("effects", key))
3169 effects = (int)atof(value);
3170 else if (r_refdef.worldmodel->type == mod_brushq3)
3172 if (!strcmp("scale", key))
3173 lightscale = atof(value);
3174 if (!strcmp("fade", key))
3175 fadescale = atof(value);
3180 if (lightscale <= 0)
3184 if (color[0] == color[1] && color[0] == color[2])
3186 color[0] *= overridecolor[0];
3187 color[1] *= overridecolor[1];
3188 color[2] *= overridecolor[2];
3190 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3191 color[0] = color[0] * light[0];
3192 color[1] = color[1] * light[1];
3193 color[2] = color[2] * light[2];
3196 case LIGHTTYPE_MINUSX:
3198 case LIGHTTYPE_RECIPX:
3200 VectorScale(color, (1.0f / 16.0f), color);
3202 case LIGHTTYPE_RECIPXX:
3204 VectorScale(color, (1.0f / 16.0f), color);
3207 case LIGHTTYPE_NONE:
3211 case LIGHTTYPE_MINUSXX:
3214 VectorAdd(origin, originhack, origin);
3216 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);
3219 Mem_Free(entfiledata);
3223 void R_Shadow_SetCursorLocationForView(void)
3226 vec3_t dest, endpos;
3228 VectorMA(r_view.origin, r_editlights_cursordistance.value, r_view.forward, dest);
3229 trace = CL_TraceBox(r_view.origin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3230 if (trace.fraction < 1)
3232 dist = trace.fraction * r_editlights_cursordistance.value;
3233 push = r_editlights_cursorpushback.value;
3237 VectorMA(trace.endpos, push, r_view.forward, endpos);
3238 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3242 VectorClear( endpos );
3244 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3245 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3246 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3249 void R_Shadow_UpdateWorldLightSelection(void)
3251 if (r_editlights.integer)
3253 R_Shadow_SetCursorLocationForView();
3254 R_Shadow_SelectLightInView();
3255 R_Shadow_DrawLightSprites();
3258 R_Shadow_SelectLight(NULL);
3261 void R_Shadow_EditLights_Clear_f(void)
3263 R_Shadow_ClearWorldLights();
3266 void R_Shadow_EditLights_Reload_f(void)
3268 if (!r_refdef.worldmodel)
3270 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3271 R_Shadow_ClearWorldLights();
3272 R_Shadow_LoadWorldLights();
3273 if (r_shadow_worldlightchain == NULL)
3275 R_Shadow_LoadLightsFile();
3276 if (r_shadow_worldlightchain == NULL)
3277 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3281 void R_Shadow_EditLights_Save_f(void)
3283 if (!r_refdef.worldmodel)
3285 R_Shadow_SaveWorldLights();
3288 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3290 R_Shadow_ClearWorldLights();
3291 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3294 void R_Shadow_EditLights_ImportLightsFile_f(void)
3296 R_Shadow_ClearWorldLights();
3297 R_Shadow_LoadLightsFile();
3300 void R_Shadow_EditLights_Spawn_f(void)
3303 if (!r_editlights.integer)
3305 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3308 if (Cmd_Argc() != 1)
3310 Con_Print("r_editlights_spawn does not take parameters\n");
3313 color[0] = color[1] = color[2] = 1;
3314 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3317 void R_Shadow_EditLights_Edit_f(void)
3319 vec3_t origin, angles, color;
3320 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3321 int style, shadows, flags, normalmode, realtimemode;
3322 char cubemapname[MAX_INPUTLINE];
3323 if (!r_editlights.integer)
3325 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3328 if (!r_shadow_selectedlight)
3330 Con_Print("No selected light.\n");
3333 VectorCopy(r_shadow_selectedlight->origin, origin);
3334 VectorCopy(r_shadow_selectedlight->angles, angles);
3335 VectorCopy(r_shadow_selectedlight->color, color);
3336 radius = r_shadow_selectedlight->radius;
3337 style = r_shadow_selectedlight->style;
3338 if (r_shadow_selectedlight->cubemapname)
3339 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3342 shadows = r_shadow_selectedlight->shadow;
3343 corona = r_shadow_selectedlight->corona;
3344 coronasizescale = r_shadow_selectedlight->coronasizescale;
3345 ambientscale = r_shadow_selectedlight->ambientscale;
3346 diffusescale = r_shadow_selectedlight->diffusescale;
3347 specularscale = r_shadow_selectedlight->specularscale;
3348 flags = r_shadow_selectedlight->flags;
3349 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3350 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3351 if (!strcmp(Cmd_Argv(1), "origin"))
3353 if (Cmd_Argc() != 5)
3355 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3358 origin[0] = atof(Cmd_Argv(2));
3359 origin[1] = atof(Cmd_Argv(3));
3360 origin[2] = atof(Cmd_Argv(4));
3362 else if (!strcmp(Cmd_Argv(1), "originx"))
3364 if (Cmd_Argc() != 3)
3366 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3369 origin[0] = atof(Cmd_Argv(2));
3371 else if (!strcmp(Cmd_Argv(1), "originy"))
3373 if (Cmd_Argc() != 3)
3375 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3378 origin[1] = atof(Cmd_Argv(2));
3380 else if (!strcmp(Cmd_Argv(1), "originz"))
3382 if (Cmd_Argc() != 3)
3384 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3387 origin[2] = atof(Cmd_Argv(2));
3389 else if (!strcmp(Cmd_Argv(1), "move"))
3391 if (Cmd_Argc() != 5)
3393 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3396 origin[0] += atof(Cmd_Argv(2));
3397 origin[1] += atof(Cmd_Argv(3));
3398 origin[2] += atof(Cmd_Argv(4));
3400 else if (!strcmp(Cmd_Argv(1), "movex"))
3402 if (Cmd_Argc() != 3)
3404 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3407 origin[0] += atof(Cmd_Argv(2));
3409 else if (!strcmp(Cmd_Argv(1), "movey"))
3411 if (Cmd_Argc() != 3)
3413 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3416 origin[1] += atof(Cmd_Argv(2));
3418 else if (!strcmp(Cmd_Argv(1), "movez"))
3420 if (Cmd_Argc() != 3)
3422 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3425 origin[2] += atof(Cmd_Argv(2));
3427 else if (!strcmp(Cmd_Argv(1), "angles"))
3429 if (Cmd_Argc() != 5)
3431 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3434 angles[0] = atof(Cmd_Argv(2));
3435 angles[1] = atof(Cmd_Argv(3));
3436 angles[2] = atof(Cmd_Argv(4));
3438 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3440 if (Cmd_Argc() != 3)
3442 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3445 angles[0] = atof(Cmd_Argv(2));
3447 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3449 if (Cmd_Argc() != 3)
3451 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3454 angles[1] = atof(Cmd_Argv(2));
3456 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3458 if (Cmd_Argc() != 3)
3460 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3463 angles[2] = atof(Cmd_Argv(2));
3465 else if (!strcmp(Cmd_Argv(1), "color"))
3467 if (Cmd_Argc() != 5)
3469 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3472 color[0] = atof(Cmd_Argv(2));
3473 color[1] = atof(Cmd_Argv(3));
3474 color[2] = atof(Cmd_Argv(4));
3476 else if (!strcmp(Cmd_Argv(1), "radius"))
3478 if (Cmd_Argc() != 3)
3480 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3483 radius = atof(Cmd_Argv(2));
3485 else if (!strcmp(Cmd_Argv(1), "colorscale"))
3487 if (Cmd_Argc() == 3)
3489 double scale = atof(Cmd_Argv(2));
3496 if (Cmd_Argc() != 5)
3498 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
3501 color[0] *= atof(Cmd_Argv(2));
3502 color[1] *= atof(Cmd_Argv(3));
3503 color[2] *= atof(Cmd_Argv(4));
3506 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
3508 if (Cmd_Argc() != 3)
3510 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3513 radius *= atof(Cmd_Argv(2));
3515 else if (!strcmp(Cmd_Argv(1), "style"))
3517 if (Cmd_Argc() != 3)
3519 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3522 style = atoi(Cmd_Argv(2));
3524 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3528 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3531 if (Cmd_Argc() == 3)
3532 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
3536 else if (!strcmp(Cmd_Argv(1), "shadows"))
3538 if (Cmd_Argc() != 3)
3540 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3543 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3545 else if (!strcmp(Cmd_Argv(1), "corona"))
3547 if (Cmd_Argc() != 3)
3549 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3552 corona = atof(Cmd_Argv(2));
3554 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3556 if (Cmd_Argc() != 3)
3558 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3561 coronasizescale = atof(Cmd_Argv(2));
3563 else if (!strcmp(Cmd_Argv(1), "ambient"))
3565 if (Cmd_Argc() != 3)
3567 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3570 ambientscale = atof(Cmd_Argv(2));
3572 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3574 if (Cmd_Argc() != 3)
3576 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3579 diffusescale = atof(Cmd_Argv(2));
3581 else if (!strcmp(Cmd_Argv(1), "specular"))
3583 if (Cmd_Argc() != 3)
3585 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3588 specularscale = atof(Cmd_Argv(2));
3590 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3592 if (Cmd_Argc() != 3)
3594 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3597 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3599 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3601 if (Cmd_Argc() != 3)
3603 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3606 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3610 Con_Print("usage: r_editlights_edit [property] [value]\n");
3611 Con_Print("Selected light's properties:\n");
3612 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3613 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3614 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3615 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3616 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3617 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3618 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3619 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3620 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3621 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3622 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3623 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3624 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3625 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3628 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3629 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3632 void R_Shadow_EditLights_EditAll_f(void)
3636 if (!r_editlights.integer)
3638 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3642 for (light = r_shadow_worldlightchain;light;light = light->next)
3644 R_Shadow_SelectLight(light);
3645 R_Shadow_EditLights_Edit_f();
3649 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3651 int lightnumber, lightcount;
3655 if (!r_editlights.integer)
3661 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3662 if (light == r_shadow_selectedlight)
3663 lightnumber = lightcount;
3664 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;
3665 if (r_shadow_selectedlight == NULL)
3667 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3668 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;
3669 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;
3670 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;
3671 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3672 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3673 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3674 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;
3675 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3676 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3677 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3678 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3679 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3680 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;
3681 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;
3684 void R_Shadow_EditLights_ToggleShadow_f(void)
3686 if (!r_editlights.integer)
3688 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3691 if (!r_shadow_selectedlight)
3693 Con_Print("No selected light.\n");
3696 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);
3699 void R_Shadow_EditLights_ToggleCorona_f(void)
3701 if (!r_editlights.integer)
3703 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3706 if (!r_shadow_selectedlight)
3708 Con_Print("No selected light.\n");
3711 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);
3714 void R_Shadow_EditLights_Remove_f(void)
3716 if (!r_editlights.integer)
3718 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3721 if (!r_shadow_selectedlight)
3723 Con_Print("No selected light.\n");
3726 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3727 r_shadow_selectedlight = NULL;
3730 void R_Shadow_EditLights_Help_f(void)
3733 "Documentation on r_editlights system:\n"
3735 "r_editlights : enable/disable editing mode\n"
3736 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3737 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3738 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3739 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3740 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3742 "r_editlights_help : this help\n"
3743 "r_editlights_clear : remove all lights\n"
3744 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3745 "r_editlights_save : save to .rtlights file\n"
3746 "r_editlights_spawn : create a light with default settings\n"
3747 "r_editlights_edit command : edit selected light - more documentation below\n"
3748 "r_editlights_remove : remove selected light\n"
3749 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3750 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3751 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3753 "origin x y z : set light location\n"
3754 "originx x: set x component of light location\n"
3755 "originy y: set y component of light location\n"
3756 "originz z: set z component of light location\n"
3757 "move x y z : adjust light location\n"
3758 "movex x: adjust x component of light location\n"
3759 "movey y: adjust y component of light location\n"
3760 "movez z: adjust z component of light location\n"
3761 "angles x y z : set light angles\n"
3762 "anglesx x: set x component of light angles\n"
3763 "anglesy y: set y component of light angles\n"
3764 "anglesz z: set z component of light angles\n"
3765 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3766 "radius radius : set radius (size) of light\n"
3767 "colorscale grey : multiply color of light (1 does nothing)\n"
3768 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
3769 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
3770 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
3771 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3772 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3773 "shadows 1/0 : turn on/off shadows\n"
3774 "corona n : set corona intensity\n"
3775 "coronasize n : set corona size (0-1)\n"
3776 "ambient n : set ambient intensity (0-1)\n"
3777 "diffuse n : set diffuse intensity (0-1)\n"
3778 "specular n : set specular intensity (0-1)\n"
3779 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
3780 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
3781 "<nothing> : print light properties to console\n"
3785 void R_Shadow_EditLights_CopyInfo_f(void)
3787 if (!r_editlights.integer)
3789 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
3792 if (!r_shadow_selectedlight)
3794 Con_Print("No selected light.\n");
3797 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
3798 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
3799 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
3800 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
3801 if (r_shadow_selectedlight->cubemapname)
3802 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
3804 r_shadow_bufferlight.cubemapname[0] = 0;
3805 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
3806 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
3807 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
3808 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
3809 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
3810 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
3811 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
3814 void R_Shadow_EditLights_PasteInfo_f(void)
3816 if (!r_editlights.integer)
3818 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
3821 if (!r_shadow_selectedlight)
3823 Con_Print("No selected light.\n");
3826 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);
3829 void R_Shadow_EditLights_Init(void)
3831 Cvar_RegisterVariable(&r_editlights);
3832 Cvar_RegisterVariable(&r_editlights_cursordistance);
3833 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3834 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3835 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3836 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3837 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
3838 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
3839 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)");
3840 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
3841 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
3842 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
3843 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)");
3844 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
3845 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
3846 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
3847 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
3848 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
3849 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
3850 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)");