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 // current light's cull box (copied out of an rtlight or calculated by GetLightInfo)
189 vec3_t r_shadow_rtlight_cullmins;
190 vec3_t r_shadow_rtlight_cullmaxs;
192 rtexturepool_t *r_shadow_texturepool;
193 rtexture_t *r_shadow_attenuation2dtexture;
194 rtexture_t *r_shadow_attenuation3dtexture;
196 // lights are reloaded when this changes
197 char r_shadow_mapname[MAX_QPATH];
199 // used only for light filters (cubemaps)
200 rtexturepool_t *r_shadow_filters_texturepool;
202 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"};
203 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"};
204 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
205 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)"};
206 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"};
207 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "2", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
208 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
209 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5", "changes attenuation texture generation (does not affect r_glsl lighting)"};
210 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1", "changes attenuation texture generation (does not affect r_glsl lighting)"};
211 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
212 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
213 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
214 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
215 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
216 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!)"};
217 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)"};
218 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"};
219 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"};
220 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
221 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
222 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"};
223 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)"};
224 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
225 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)"};
226 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)"};
227 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatetencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
228 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
229 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
230 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
231 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
232 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
233 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
234 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
236 float r_shadow_attenpower, r_shadow_attenscale;
238 rtlight_t *r_shadow_compilingrtlight;
239 dlight_t *r_shadow_worldlightchain;
240 dlight_t *r_shadow_selectedlight;
241 dlight_t r_shadow_bufferlight;
242 vec3_t r_editlights_cursorlocation;
244 extern int con_vislines;
246 typedef struct cubemapinfo_s
253 #define MAX_CUBEMAPS 256
254 static int numcubemaps;
255 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
257 void R_Shadow_UncompileWorldLights(void);
258 void R_Shadow_ClearWorldLights(void);
259 void R_Shadow_SaveWorldLights(void);
260 void R_Shadow_LoadWorldLights(void);
261 void R_Shadow_LoadLightsFile(void);
262 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
263 void R_Shadow_EditLights_Reload_f(void);
264 void R_Shadow_ValidateCvars(void);
265 static void R_Shadow_MakeTextures(void);
266 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
268 void r_shadow_start(void)
270 // allocate vertex processing arrays
272 r_shadow_attenuation2dtexture = NULL;
273 r_shadow_attenuation3dtexture = NULL;
274 r_shadow_texturepool = NULL;
275 r_shadow_filters_texturepool = NULL;
276 R_Shadow_ValidateCvars();
277 R_Shadow_MakeTextures();
278 maxshadowtriangles = 0;
279 shadowelements = NULL;
280 maxshadowvertices = 0;
281 shadowvertex3f = NULL;
289 shadowmarklist = NULL;
291 r_shadow_buffer_numleafpvsbytes = 0;
292 r_shadow_buffer_leafpvs = NULL;
293 r_shadow_buffer_leaflist = NULL;
294 r_shadow_buffer_numsurfacepvsbytes = 0;
295 r_shadow_buffer_surfacepvs = NULL;
296 r_shadow_buffer_surfacelist = NULL;
299 void r_shadow_shutdown(void)
301 R_Shadow_UncompileWorldLights();
303 r_shadow_attenuation2dtexture = NULL;
304 r_shadow_attenuation3dtexture = NULL;
305 R_FreeTexturePool(&r_shadow_texturepool);
306 R_FreeTexturePool(&r_shadow_filters_texturepool);
307 maxshadowtriangles = 0;
309 Mem_Free(shadowelements);
310 shadowelements = NULL;
312 Mem_Free(shadowvertex3f);
313 shadowvertex3f = NULL;
316 Mem_Free(vertexupdate);
319 Mem_Free(vertexremap);
325 Mem_Free(shadowmark);
328 Mem_Free(shadowmarklist);
329 shadowmarklist = NULL;
331 r_shadow_buffer_numleafpvsbytes = 0;
332 if (r_shadow_buffer_leafpvs)
333 Mem_Free(r_shadow_buffer_leafpvs);
334 r_shadow_buffer_leafpvs = NULL;
335 if (r_shadow_buffer_leaflist)
336 Mem_Free(r_shadow_buffer_leaflist);
337 r_shadow_buffer_leaflist = NULL;
338 r_shadow_buffer_numsurfacepvsbytes = 0;
339 if (r_shadow_buffer_surfacepvs)
340 Mem_Free(r_shadow_buffer_surfacepvs);
341 r_shadow_buffer_surfacepvs = NULL;
342 if (r_shadow_buffer_surfacelist)
343 Mem_Free(r_shadow_buffer_surfacelist);
344 r_shadow_buffer_surfacelist = NULL;
347 void r_shadow_newmap(void)
351 void R_Shadow_Help_f(void)
354 "Documentation on r_shadow system:\n"
356 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
357 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
358 "r_shadow_debuglight : render only this light number (-1 = all)\n"
359 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
360 "r_shadow_gloss2intensity : brightness of forced gloss\n"
361 "r_shadow_glossintensity : brightness of textured gloss\n"
362 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
363 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
364 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
365 "r_shadow_portallight : use portal visibility for static light precomputation\n"
366 "r_shadow_projectdistance : shadow volume projection distance\n"
367 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
368 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
369 "r_shadow_realtime_dlight_portalculling : work hard to reduce graphics work\n"
370 "r_shadow_realtime_world : use high quality world lighting mode\n"
371 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
372 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
373 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
374 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
375 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
376 "r_shadow_scissor : use scissor optimization\n"
377 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
378 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
379 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
380 "r_showlighting : useful for performance testing; bright = slow!\n"
381 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
383 "r_shadow_help : this help\n"
387 void R_Shadow_Init(void)
389 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
390 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
391 Cvar_RegisterVariable(&r_shadow_debuglight);
392 Cvar_RegisterVariable(&r_shadow_gloss);
393 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
394 Cvar_RegisterVariable(&r_shadow_glossintensity);
395 Cvar_RegisterVariable(&r_shadow_glossexponent);
396 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
397 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
398 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
399 Cvar_RegisterVariable(&r_shadow_portallight);
400 Cvar_RegisterVariable(&r_shadow_projectdistance);
401 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
402 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
403 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
404 Cvar_RegisterVariable(&r_shadow_realtime_world);
405 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
406 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
407 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
408 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
409 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
410 Cvar_RegisterVariable(&r_shadow_scissor);
411 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
412 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
413 Cvar_RegisterVariable(&r_shadow_texture3d);
414 Cvar_RegisterVariable(&gl_ext_separatestencil);
415 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
416 if (gamemode == GAME_TENEBRAE)
418 Cvar_SetValue("r_shadow_gloss", 2);
419 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
421 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
422 R_Shadow_EditLights_Init();
423 r_shadow_worldlightchain = NULL;
424 maxshadowtriangles = 0;
425 shadowelements = NULL;
426 maxshadowvertices = 0;
427 shadowvertex3f = NULL;
435 shadowmarklist = NULL;
437 r_shadow_buffer_numleafpvsbytes = 0;
438 r_shadow_buffer_leafpvs = NULL;
439 r_shadow_buffer_leaflist = NULL;
440 r_shadow_buffer_numsurfacepvsbytes = 0;
441 r_shadow_buffer_surfacepvs = NULL;
442 r_shadow_buffer_surfacelist = NULL;
443 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
446 matrix4x4_t matrix_attenuationxyz =
449 {0.5, 0.0, 0.0, 0.5},
450 {0.0, 0.5, 0.0, 0.5},
451 {0.0, 0.0, 0.5, 0.5},
456 matrix4x4_t matrix_attenuationz =
459 {0.0, 0.0, 0.5, 0.5},
460 {0.0, 0.0, 0.0, 0.5},
461 {0.0, 0.0, 0.0, 0.5},
466 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
468 // make sure shadowelements is big enough for this volume
469 if (maxshadowtriangles < numtriangles)
471 maxshadowtriangles = numtriangles;
473 Mem_Free(shadowelements);
474 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
476 // make sure shadowvertex3f is big enough for this volume
477 if (maxshadowvertices < numvertices)
479 maxshadowvertices = numvertices;
481 Mem_Free(shadowvertex3f);
482 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
486 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
488 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
489 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
490 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
492 if (r_shadow_buffer_leafpvs)
493 Mem_Free(r_shadow_buffer_leafpvs);
494 if (r_shadow_buffer_leaflist)
495 Mem_Free(r_shadow_buffer_leaflist);
496 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
497 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
498 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
500 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
502 if (r_shadow_buffer_surfacepvs)
503 Mem_Free(r_shadow_buffer_surfacepvs);
504 if (r_shadow_buffer_surfacelist)
505 Mem_Free(r_shadow_buffer_surfacelist);
506 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
507 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
508 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
512 void R_Shadow_PrepareShadowMark(int numtris)
514 // make sure shadowmark is big enough for this volume
515 if (maxshadowmark < numtris)
517 maxshadowmark = numtris;
519 Mem_Free(shadowmark);
521 Mem_Free(shadowmarklist);
522 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
523 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
527 // if shadowmarkcount wrapped we clear the array and adjust accordingly
528 if (shadowmarkcount == 0)
531 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
536 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)
539 int outtriangles = 0, outvertices = 0;
542 float ratio, direction[3], projectvector[3];
544 if (projectdirection)
545 VectorScale(projectdirection, projectdistance, projectvector);
547 VectorClear(projectvector);
549 if (maxvertexupdate < innumvertices)
551 maxvertexupdate = innumvertices;
553 Mem_Free(vertexupdate);
555 Mem_Free(vertexremap);
556 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
557 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
561 if (vertexupdatenum == 0)
564 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
565 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
568 for (i = 0;i < numshadowmarktris;i++)
569 shadowmark[shadowmarktris[i]] = shadowmarkcount;
571 // create the vertices
572 if (projectdirection)
574 for (i = 0;i < numshadowmarktris;i++)
576 element = inelement3i + shadowmarktris[i] * 3;
577 for (j = 0;j < 3;j++)
579 if (vertexupdate[element[j]] != vertexupdatenum)
581 vertexupdate[element[j]] = vertexupdatenum;
582 vertexremap[element[j]] = outvertices;
583 vertex = invertex3f + element[j] * 3;
584 // project one copy of the vertex according to projectvector
585 VectorCopy(vertex, outvertex3f);
586 VectorAdd(vertex, projectvector, (outvertex3f + 3));
595 for (i = 0;i < numshadowmarktris;i++)
597 element = inelement3i + shadowmarktris[i] * 3;
598 for (j = 0;j < 3;j++)
600 if (vertexupdate[element[j]] != vertexupdatenum)
602 vertexupdate[element[j]] = vertexupdatenum;
603 vertexremap[element[j]] = outvertices;
604 vertex = invertex3f + element[j] * 3;
605 // project one copy of the vertex to the sphere radius of the light
606 // (FIXME: would projecting it to the light box be better?)
607 VectorSubtract(vertex, projectorigin, direction);
608 ratio = projectdistance / VectorLength(direction);
609 VectorCopy(vertex, outvertex3f);
610 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
618 for (i = 0;i < numshadowmarktris;i++)
620 int remappedelement[3];
622 const int *neighbortriangle;
624 markindex = shadowmarktris[i] * 3;
625 element = inelement3i + markindex;
626 neighbortriangle = inneighbor3i + markindex;
627 // output the front and back triangles
628 outelement3i[0] = vertexremap[element[0]];
629 outelement3i[1] = vertexremap[element[1]];
630 outelement3i[2] = vertexremap[element[2]];
631 outelement3i[3] = vertexremap[element[2]] + 1;
632 outelement3i[4] = vertexremap[element[1]] + 1;
633 outelement3i[5] = vertexremap[element[0]] + 1;
637 // output the sides (facing outward from this triangle)
638 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
640 remappedelement[0] = vertexremap[element[0]];
641 remappedelement[1] = vertexremap[element[1]];
642 outelement3i[0] = remappedelement[1];
643 outelement3i[1] = remappedelement[0];
644 outelement3i[2] = remappedelement[0] + 1;
645 outelement3i[3] = remappedelement[1];
646 outelement3i[4] = remappedelement[0] + 1;
647 outelement3i[5] = remappedelement[1] + 1;
652 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
654 remappedelement[1] = vertexremap[element[1]];
655 remappedelement[2] = vertexremap[element[2]];
656 outelement3i[0] = remappedelement[2];
657 outelement3i[1] = remappedelement[1];
658 outelement3i[2] = remappedelement[1] + 1;
659 outelement3i[3] = remappedelement[2];
660 outelement3i[4] = remappedelement[1] + 1;
661 outelement3i[5] = remappedelement[2] + 1;
666 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
668 remappedelement[0] = vertexremap[element[0]];
669 remappedelement[2] = vertexremap[element[2]];
670 outelement3i[0] = remappedelement[0];
671 outelement3i[1] = remappedelement[2];
672 outelement3i[2] = remappedelement[2] + 1;
673 outelement3i[3] = remappedelement[0];
674 outelement3i[4] = remappedelement[2] + 1;
675 outelement3i[5] = remappedelement[0] + 1;
682 *outnumvertices = outvertices;
686 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)
689 if (projectdistance < 0.1)
691 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
694 if (!numverts || !nummarktris)
696 // make sure shadowelements is big enough for this volume
697 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
698 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
699 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
700 r_refdef.stats.lights_dynamicshadowtriangles += tris;
701 R_Shadow_RenderVolume(outverts, tris, shadowvertex3f, shadowelements);
704 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)
710 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
712 tend = firsttriangle + numtris;
713 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
714 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
715 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
717 // surface box entirely inside light box, no box cull
718 if (projectdirection)
720 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
722 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
723 if (DotProduct(normal, projectdirection) < 0)
724 shadowmarklist[numshadowmark++] = t;
729 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
730 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
731 shadowmarklist[numshadowmark++] = t;
736 // surface box not entirely inside light box, cull each triangle
737 if (projectdirection)
739 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
741 v[0] = invertex3f + e[0] * 3;
742 v[1] = invertex3f + e[1] * 3;
743 v[2] = invertex3f + e[2] * 3;
744 TriangleNormal(v[0], v[1], v[2], normal);
745 if (DotProduct(normal, projectdirection) < 0
746 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
747 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
748 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
749 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
750 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
751 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
752 shadowmarklist[numshadowmark++] = t;
757 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
759 v[0] = invertex3f + e[0] * 3;
760 v[1] = invertex3f + e[1] * 3;
761 v[2] = invertex3f + e[2] * 3;
762 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
763 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
764 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
765 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
766 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
767 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
768 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
769 shadowmarklist[numshadowmark++] = t;
775 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
777 if (r_shadow_compilingrtlight)
779 // if we're compiling an rtlight, capture the mesh
780 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
783 r_refdef.stats.lights_shadowtriangles += numtriangles;
785 R_Mesh_VertexPointer(vertex3f);
786 GL_LockArrays(0, numvertices);
787 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
789 // decrement stencil if backface is behind depthbuffer
790 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
791 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
792 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
793 // increment stencil if frontface is behind depthbuffer
794 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
795 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
797 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
802 static void R_Shadow_MakeTextures(void)
805 float v[3], intensity;
807 R_FreeTexturePool(&r_shadow_texturepool);
808 r_shadow_texturepool = R_AllocTexturePool();
809 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
810 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
811 #define ATTEN2DSIZE 64
812 #define ATTEN3DSIZE 32
813 data = (unsigned char *)Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
814 for (y = 0;y < ATTEN2DSIZE;y++)
816 for (x = 0;x < ATTEN2DSIZE;x++)
818 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
819 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
821 intensity = 1.0f - sqrt(DotProduct(v, v));
823 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
824 d = (int)bound(0, intensity, 255);
825 data[(y*ATTEN2DSIZE+x)*4+0] = d;
826 data[(y*ATTEN2DSIZE+x)*4+1] = d;
827 data[(y*ATTEN2DSIZE+x)*4+2] = d;
828 data[(y*ATTEN2DSIZE+x)*4+3] = d;
831 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
832 if (r_shadow_texture3d.integer && gl_texture3d)
834 for (z = 0;z < ATTEN3DSIZE;z++)
836 for (y = 0;y < ATTEN3DSIZE;y++)
838 for (x = 0;x < ATTEN3DSIZE;x++)
840 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
841 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
842 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
843 intensity = 1.0f - sqrt(DotProduct(v, v));
845 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
846 d = (int)bound(0, intensity, 255);
847 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
848 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
849 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
850 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
854 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
859 void R_Shadow_ValidateCvars(void)
861 if (r_shadow_texture3d.integer && !gl_texture3d)
862 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
863 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
864 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
865 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
866 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
869 // light currently being rendered
870 rtlight_t *r_shadow_rtlight;
872 // this is the location of the light in entity space
873 vec3_t r_shadow_entitylightorigin;
874 // this transforms entity coordinates to light filter cubemap coordinates
875 // (also often used for other purposes)
876 matrix4x4_t r_shadow_entitytolight;
877 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
878 // of attenuation texturing in full 3D (Z result often ignored)
879 matrix4x4_t r_shadow_entitytoattenuationxyz;
880 // this transforms only the Z to S, and T is always 0.5
881 matrix4x4_t r_shadow_entitytoattenuationz;
883 void R_Shadow_RenderMode_Begin(void)
885 R_Shadow_ValidateCvars();
887 if (!r_shadow_attenuation2dtexture
888 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
889 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
890 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
891 R_Shadow_MakeTextures();
894 R_Mesh_ColorPointer(NULL);
895 R_Mesh_ResetTextureState();
896 GL_BlendFunc(GL_ONE, GL_ZERO);
899 GL_Color(0, 0, 0, 1);
900 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
902 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
904 if (gl_ext_separatestencil.integer)
905 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
906 else if (gl_ext_stenciltwoside.integer)
907 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
909 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
911 if (r_glsl.integer && gl_support_fragment_shader)
912 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
913 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
914 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
916 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
919 void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
921 r_shadow_rtlight = rtlight;
924 void R_Shadow_RenderMode_Reset(void)
927 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
929 qglUseProgramObjectARB(0);CHECKGLERROR
931 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
933 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
935 R_Mesh_ColorPointer(NULL);
936 R_Mesh_ResetTextureState();
939 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
940 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
941 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
942 qglStencilMask(~0);CHECKGLERROR
943 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
944 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
945 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
946 GL_Color(1, 1, 1, 1);
947 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
948 GL_BlendFunc(GL_ONE, GL_ZERO);
951 void R_Shadow_RenderMode_StencilShadowVolumes(void)
954 R_Shadow_RenderMode_Reset();
955 GL_ColorMask(0, 0, 0, 0);
956 qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
957 qglDepthFunc(GL_LESS);CHECKGLERROR
958 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
959 r_shadow_rendermode = r_shadow_shadowingrendermode;
960 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SEPARATESTENCIL)
962 GL_CullFace(GL_NONE);
963 qglStencilOpSeparate(GL_BACK, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR // quake is backwards, this is front faces
964 qglStencilOpSeparate(GL_FRONT, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR // quake is backwards, this is back faces
966 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
968 GL_CullFace(GL_NONE);
969 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
970 qglActiveStencilFaceEXT(GL_BACK);CHECKGLERROR // quake is backwards, this is front faces
971 qglStencilMask(~0);CHECKGLERROR
972 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
973 qglActiveStencilFaceEXT(GL_FRONT);CHECKGLERROR // quake is backwards, this is back faces
974 qglStencilMask(~0);CHECKGLERROR
975 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
977 GL_Clear(GL_STENCIL_BUFFER_BIT);
978 r_refdef.stats.lights_clears++;
981 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
984 R_Shadow_RenderMode_Reset();
985 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
988 qglDepthFunc(GL_EQUAL);CHECKGLERROR
992 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
993 // only draw light where this geometry was already rendered AND the
994 // stencil is 128 (values other than this mean shadow)
995 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
997 r_shadow_rendermode = r_shadow_lightingrendermode;
998 // do global setup needed for the chosen lighting mode
999 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1001 R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
1002 R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
1003 R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
1004 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_rtlight->currentcubemap)); // light filter
1005 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
1006 R_Mesh_TexBind(5, R_GetTexture(r_texture_white)); // pants
1007 R_Mesh_TexBind(6, R_GetTexture(r_texture_white)); // shirt
1008 R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); // lightmap
1009 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); // deluxemap
1010 R_Mesh_TexBind(9, R_GetTexture(r_texture_black)); // glow
1011 //R_Mesh_TexMatrix(3, r_shadow_entitytolight); // light filter matrix
1012 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1013 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1018 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1021 R_Shadow_RenderMode_Reset();
1022 GL_BlendFunc(GL_ONE, GL_ONE);
1023 GL_DepthTest(r_showshadowvolumes.integer < 2);
1024 GL_Color(0.0, 0.0125 * r_view.colorscale, 0.1 * r_view.colorscale, 1);
1025 qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1026 GL_CullFace(GL_NONE);
1027 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1030 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1033 R_Shadow_RenderMode_Reset();
1034 GL_BlendFunc(GL_ONE, GL_ONE);
1035 GL_DepthTest(r_showlighting.integer < 2);
1036 GL_Color(0.1 * r_view.colorscale, 0.0125 * r_view.colorscale, 0, 1);
1039 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1043 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1045 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1048 void R_Shadow_RenderMode_End(void)
1051 R_Shadow_RenderMode_Reset();
1052 R_Shadow_RenderMode_ActiveLight(NULL);
1054 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1055 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1058 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1060 int i, ix1, iy1, ix2, iy2;
1061 float x1, y1, x2, y2;
1064 mplane_t planes[11];
1065 float vertex3f[256*3];
1067 // if view is inside the light box, just say yes it's visible
1068 if (BoxesOverlap(r_view.origin, r_view.origin, mins, maxs))
1070 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1074 // create a temporary brush describing the area the light can affect in worldspace
1075 VectorNegate(r_view.frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -r_view.frustum[0].dist;
1076 VectorNegate(r_view.frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -r_view.frustum[1].dist;
1077 VectorNegate(r_view.frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -r_view.frustum[2].dist;
1078 VectorNegate(r_view.frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -r_view.frustum[3].dist;
1079 VectorNegate(r_view.frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -r_view.frustum[4].dist;
1080 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1081 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1082 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1083 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1084 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1085 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1087 // turn the brush into a mesh
1088 memset(&mesh, 0, sizeof(rmesh_t));
1089 mesh.maxvertices = 256;
1090 mesh.vertex3f = vertex3f;
1091 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1092 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1094 // if that mesh is empty, the light is not visible at all
1095 if (!mesh.numvertices)
1098 if (!r_shadow_scissor.integer)
1101 // if that mesh is not empty, check what area of the screen it covers
1102 x1 = y1 = x2 = y2 = 0;
1104 //Con_Printf("%i vertices to transform...\n", mesh.numvertices);
1105 for (i = 0;i < mesh.numvertices;i++)
1107 VectorCopy(mesh.vertex3f + i * 3, v);
1108 GL_TransformToScreen(v, v2);
1109 //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]);
1112 if (x1 > v2[0]) x1 = v2[0];
1113 if (x2 < v2[0]) x2 = v2[0];
1114 if (y1 > v2[1]) y1 = v2[1];
1115 if (y2 < v2[1]) y2 = v2[1];
1124 // now convert the scissor rectangle to integer screen coordinates
1125 ix1 = (int)(x1 - 1.0f);
1126 iy1 = (int)(y1 - 1.0f);
1127 ix2 = (int)(x2 + 1.0f);
1128 iy2 = (int)(y2 + 1.0f);
1129 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1131 // clamp it to the screen
1132 if (ix1 < r_view.x) ix1 = r_view.x;
1133 if (iy1 < r_view.y) iy1 = r_view.y;
1134 if (ix2 > r_view.x + r_view.width) ix2 = r_view.x + r_view.width;
1135 if (iy2 > r_view.y + r_view.height) iy2 = r_view.y + r_view.height;
1137 // if it is inside out, it's not visible
1138 if (ix2 <= ix1 || iy2 <= iy1)
1141 // the light area is visible, set up the scissor rectangle
1142 GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1143 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1144 //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1145 r_refdef.stats.lights_scissored++;
1149 static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor)
1151 int numverts = surface->num_vertices;
1152 float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1153 float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1154 float *color4f = rsurface_array_color4f + 4 * surface->num_firstvertex;
1155 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1156 if (r_textureunits.integer >= 3)
1158 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1160 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1161 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1162 if ((dot = DotProduct(n, v)) < 0)
1164 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1165 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]);
1166 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]);
1167 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]);
1168 if (r_refdef.fogenabled)
1170 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1171 VectorScale(color4f, f, color4f);
1175 VectorClear(color4f);
1179 else if (r_textureunits.integer >= 2)
1181 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1183 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1184 if ((dist = fabs(v[2])) < 1)
1186 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1187 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1188 if ((dot = DotProduct(n, v)) < 0)
1190 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1191 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1192 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1193 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1197 color4f[0] = ambientcolor[0] * distintensity;
1198 color4f[1] = ambientcolor[1] * distintensity;
1199 color4f[2] = ambientcolor[2] * distintensity;
1201 if (r_refdef.fogenabled)
1203 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1204 VectorScale(color4f, f, color4f);
1208 VectorClear(color4f);
1214 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1216 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1217 if ((dist = DotProduct(v, v)) < 1)
1220 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1221 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1222 if ((dot = DotProduct(n, v)) < 0)
1224 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1225 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1226 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1227 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1231 color4f[0] = ambientcolor[0] * distintensity;
1232 color4f[1] = ambientcolor[1] * distintensity;
1233 color4f[2] = ambientcolor[2] * distintensity;
1235 if (r_refdef.fogenabled)
1237 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1238 VectorScale(color4f, f, color4f);
1242 VectorClear(color4f);
1248 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1250 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int numsurfaces, msurface_t **surfacelist)
1252 int surfacelistindex;
1253 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1255 const msurface_t *surface = surfacelist[surfacelistindex];
1257 float *out3f = rsurface_array_texcoord3f + 3 * surface->num_firstvertex;
1258 const float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1259 const float *svector3f = rsurface_svector3f + 3 * surface->num_firstvertex;
1260 const float *tvector3f = rsurface_tvector3f + 3 * surface->num_firstvertex;
1261 const float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1263 for (i = 0;i < surface->num_vertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1265 VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1266 // the cubemap normalizes this for us
1267 out3f[0] = DotProduct(svector3f, lightdir);
1268 out3f[1] = DotProduct(tvector3f, lightdir);
1269 out3f[2] = DotProduct(normal3f, lightdir);
1274 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int numsurfaces, msurface_t **surfacelist)
1276 int surfacelistindex;
1277 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1279 const msurface_t *surface = surfacelist[surfacelistindex];
1281 float *out3f = rsurface_array_texcoord3f + 3 * surface->num_firstvertex;
1282 const float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1283 const float *svector3f = rsurface_svector3f + 3 * surface->num_firstvertex;
1284 const float *tvector3f = rsurface_tvector3f + 3 * surface->num_firstvertex;
1285 const float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1286 float lightdir[3], eyedir[3], halfdir[3];
1287 for (i = 0;i < surface->num_vertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1289 VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1290 VectorNormalize(lightdir);
1291 VectorSubtract(rsurface_modelorg, vertex3f, eyedir);
1292 VectorNormalize(eyedir);
1293 VectorAdd(lightdir, eyedir, halfdir);
1294 // the cubemap normalizes this for us
1295 out3f[0] = DotProduct(svector3f, halfdir);
1296 out3f[1] = DotProduct(tvector3f, halfdir);
1297 out3f[2] = DotProduct(normal3f, halfdir);
1302 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)
1304 // used to display how many times a surface is lit for level design purposes
1305 GL_Color(0.1 * r_view.colorscale, 0.025 * r_view.colorscale, 0, 1);
1306 R_Mesh_ColorPointer(NULL);
1307 R_Mesh_ResetTextureState();
1308 RSurf_PrepareVerticesForBatch(false, false, numsurfaces, surfacelist);
1309 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1310 GL_LockArrays(0, 0);
1313 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)
1315 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1316 RSurf_PrepareVerticesForBatch(true, true, numsurfaces, surfacelist);
1317 R_SetupSurfaceShader(lightcolorbase, false);
1318 R_Mesh_TexCoordPointer(0, 2, rsurface_model->surfmesh.data_texcoordtexture2f);
1319 R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
1320 R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
1321 R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
1322 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1324 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1326 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1327 GL_LockArrays(0, 0);
1328 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1330 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1334 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(int numsurfaces, msurface_t **surfacelist, float r, float g, float b)
1336 // shared final code for all the dot3 layers
1338 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1339 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1341 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1342 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1343 GL_LockArrays(0, 0);
1347 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
1350 // colorscale accounts for how much we multiply the brightness
1353 // mult is how many times the final pass of the lighting will be
1354 // performed to get more brightness than otherwise possible.
1356 // Limit mult to 64 for sanity sake.
1358 if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1360 // 3 3D combine path (Geforce3, Radeon 8500)
1361 memset(&m, 0, sizeof(m));
1362 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1363 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1364 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1365 m.tex[1] = R_GetTexture(basetexture);
1366 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1367 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1368 m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1369 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1370 m.texmatrix[2] = r_shadow_entitytolight;
1371 GL_BlendFunc(GL_ONE, GL_ONE);
1373 else if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1375 // 2 3D combine path (Geforce3, original Radeon)
1376 memset(&m, 0, sizeof(m));
1377 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1378 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1379 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1380 m.tex[1] = R_GetTexture(basetexture);
1381 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1382 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1383 GL_BlendFunc(GL_ONE, GL_ONE);
1385 else if (r_textureunits.integer >= 4 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1387 // 4 2D combine path (Geforce3, Radeon 8500)
1388 memset(&m, 0, sizeof(m));
1389 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1390 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1391 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1392 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1393 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1394 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1395 m.tex[2] = R_GetTexture(basetexture);
1396 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1397 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1398 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1400 m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1401 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1402 m.texmatrix[3] = r_shadow_entitytolight;
1404 GL_BlendFunc(GL_ONE, GL_ONE);
1406 else if (r_textureunits.integer >= 3 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1408 // 3 2D combine path (Geforce3, original Radeon)
1409 memset(&m, 0, sizeof(m));
1410 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1411 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1412 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1413 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1414 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1415 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1416 m.tex[2] = R_GetTexture(basetexture);
1417 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1418 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1419 GL_BlendFunc(GL_ONE, GL_ONE);
1423 // 2/2/2 2D combine path (any dot3 card)
1424 memset(&m, 0, sizeof(m));
1425 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1426 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1427 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1428 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1429 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1430 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1431 R_Mesh_TextureState(&m);
1432 GL_ColorMask(0,0,0,1);
1433 GL_BlendFunc(GL_ONE, GL_ZERO);
1434 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1435 GL_LockArrays(0, 0);
1438 memset(&m, 0, sizeof(m));
1439 m.tex[0] = R_GetTexture(basetexture);
1440 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1441 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1442 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1444 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1445 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1446 m.texmatrix[1] = r_shadow_entitytolight;
1448 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1450 // this final code is shared
1451 R_Mesh_TextureState(&m);
1452 R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1455 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)
1458 // colorscale accounts for how much we multiply the brightness
1461 // mult is how many times the final pass of the lighting will be
1462 // performed to get more brightness than otherwise possible.
1464 // Limit mult to 64 for sanity sake.
1466 // generate normalization cubemap texcoords
1467 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(numsurfaces, surfacelist);
1468 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1470 // 3/2 3D combine path (Geforce3, Radeon 8500)
1471 memset(&m, 0, sizeof(m));
1472 m.tex[0] = R_GetTexture(normalmaptexture);
1473 m.texcombinergb[0] = GL_REPLACE;
1474 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1475 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1476 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1477 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1478 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1479 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1480 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1481 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1482 R_Mesh_TextureState(&m);
1483 GL_ColorMask(0,0,0,1);
1484 GL_BlendFunc(GL_ONE, GL_ZERO);
1485 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1486 GL_LockArrays(0, 0);
1489 memset(&m, 0, sizeof(m));
1490 m.tex[0] = R_GetTexture(basetexture);
1491 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1492 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1493 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1495 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1496 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1497 m.texmatrix[1] = r_shadow_entitytolight;
1499 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1501 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1503 // 1/2/2 3D combine path (original Radeon)
1504 memset(&m, 0, sizeof(m));
1505 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1506 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1507 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1508 R_Mesh_TextureState(&m);
1509 GL_ColorMask(0,0,0,1);
1510 GL_BlendFunc(GL_ONE, GL_ZERO);
1511 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1512 GL_LockArrays(0, 0);
1515 memset(&m, 0, sizeof(m));
1516 m.tex[0] = R_GetTexture(normalmaptexture);
1517 m.texcombinergb[0] = GL_REPLACE;
1518 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1519 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1520 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1521 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1522 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1523 R_Mesh_TextureState(&m);
1524 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1525 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1526 GL_LockArrays(0, 0);
1529 memset(&m, 0, sizeof(m));
1530 m.tex[0] = R_GetTexture(basetexture);
1531 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1532 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1533 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1535 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1536 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1537 m.texmatrix[1] = r_shadow_entitytolight;
1539 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1541 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1543 // 2/2 3D combine path (original Radeon)
1544 memset(&m, 0, sizeof(m));
1545 m.tex[0] = R_GetTexture(normalmaptexture);
1546 m.texcombinergb[0] = GL_REPLACE;
1547 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1548 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1549 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1550 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1551 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1552 R_Mesh_TextureState(&m);
1553 GL_ColorMask(0,0,0,1);
1554 GL_BlendFunc(GL_ONE, GL_ZERO);
1555 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1556 GL_LockArrays(0, 0);
1559 memset(&m, 0, sizeof(m));
1560 m.tex[0] = R_GetTexture(basetexture);
1561 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1562 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1563 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1564 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1565 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1566 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1568 else if (r_textureunits.integer >= 4)
1570 // 4/2 2D combine path (Geforce3, Radeon 8500)
1571 memset(&m, 0, sizeof(m));
1572 m.tex[0] = R_GetTexture(normalmaptexture);
1573 m.texcombinergb[0] = GL_REPLACE;
1574 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1575 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1576 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1577 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1578 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1579 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1580 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1581 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1582 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1583 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1584 m.texmatrix[3] = r_shadow_entitytoattenuationz;
1585 R_Mesh_TextureState(&m);
1586 GL_ColorMask(0,0,0,1);
1587 GL_BlendFunc(GL_ONE, GL_ZERO);
1588 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1589 GL_LockArrays(0, 0);
1592 memset(&m, 0, sizeof(m));
1593 m.tex[0] = R_GetTexture(basetexture);
1594 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1595 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1596 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1598 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1599 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1600 m.texmatrix[1] = r_shadow_entitytolight;
1602 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1606 // 2/2/2 2D combine path (any dot3 card)
1607 memset(&m, 0, sizeof(m));
1608 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1609 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1610 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1611 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1612 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1613 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1614 R_Mesh_TextureState(&m);
1615 GL_ColorMask(0,0,0,1);
1616 GL_BlendFunc(GL_ONE, GL_ZERO);
1617 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1618 GL_LockArrays(0, 0);
1621 memset(&m, 0, sizeof(m));
1622 m.tex[0] = R_GetTexture(normalmaptexture);
1623 m.texcombinergb[0] = GL_REPLACE;
1624 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1625 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1626 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1627 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1628 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1629 R_Mesh_TextureState(&m);
1630 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1631 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1632 GL_LockArrays(0, 0);
1635 memset(&m, 0, sizeof(m));
1636 m.tex[0] = R_GetTexture(basetexture);
1637 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1638 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1639 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1641 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1642 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1643 m.texmatrix[1] = r_shadow_entitytolight;
1645 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1647 // this final code is shared
1648 R_Mesh_TextureState(&m);
1649 R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1652 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)
1654 float glossexponent;
1656 // FIXME: detect blendsquare!
1657 //if (!gl_support_blendsquare)
1660 // generate normalization cubemap texcoords
1661 R_Shadow_GenTexCoords_Specular_NormalCubeMap(numsurfaces, surfacelist);
1662 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1664 // 2/0/0/1/2 3D combine blendsquare path
1665 memset(&m, 0, sizeof(m));
1666 m.tex[0] = R_GetTexture(normalmaptexture);
1667 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1668 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1669 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1670 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1671 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1672 R_Mesh_TextureState(&m);
1673 GL_ColorMask(0,0,0,1);
1674 // this squares the result
1675 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1676 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1677 GL_LockArrays(0, 0);
1679 // second and third pass
1680 R_Mesh_ResetTextureState();
1681 // square alpha in framebuffer a few times to make it shiny
1682 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1683 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1684 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1685 GL_LockArrays(0, 0);
1688 memset(&m, 0, sizeof(m));
1689 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1690 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1691 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1692 R_Mesh_TextureState(&m);
1693 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1694 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1695 GL_LockArrays(0, 0);
1698 memset(&m, 0, sizeof(m));
1699 m.tex[0] = R_GetTexture(glosstexture);
1700 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1701 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1702 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1704 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1705 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1706 m.texmatrix[1] = r_shadow_entitytolight;
1708 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1710 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1712 // 2/0/0/2 3D combine blendsquare path
1713 memset(&m, 0, sizeof(m));
1714 m.tex[0] = R_GetTexture(normalmaptexture);
1715 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1716 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1717 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1718 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1719 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1720 R_Mesh_TextureState(&m);
1721 GL_ColorMask(0,0,0,1);
1722 // this squares the result
1723 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1724 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1725 GL_LockArrays(0, 0);
1727 // second and third pass
1728 R_Mesh_ResetTextureState();
1729 // square alpha in framebuffer a few times to make it shiny
1730 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1731 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1732 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1733 GL_LockArrays(0, 0);
1736 memset(&m, 0, sizeof(m));
1737 m.tex[0] = R_GetTexture(glosstexture);
1738 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1739 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1740 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1741 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1742 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1743 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1747 // 2/0/0/2/2 2D combine blendsquare path
1748 memset(&m, 0, sizeof(m));
1749 m.tex[0] = R_GetTexture(normalmaptexture);
1750 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1751 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1752 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1753 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1754 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1755 R_Mesh_TextureState(&m);
1756 GL_ColorMask(0,0,0,1);
1757 // this squares the result
1758 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1759 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1760 GL_LockArrays(0, 0);
1762 // second and third pass
1763 R_Mesh_ResetTextureState();
1764 // square alpha in framebuffer a few times to make it shiny
1765 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1766 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1767 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1768 GL_LockArrays(0, 0);
1771 memset(&m, 0, sizeof(m));
1772 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1773 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1774 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1775 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1776 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1777 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1778 R_Mesh_TextureState(&m);
1779 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1780 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1781 GL_LockArrays(0, 0);
1784 memset(&m, 0, sizeof(m));
1785 m.tex[0] = R_GetTexture(glosstexture);
1786 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1787 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1788 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1790 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1791 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1792 m.texmatrix[1] = r_shadow_entitytolight;
1794 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1796 // this final code is shared
1797 R_Mesh_TextureState(&m);
1798 R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1801 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)
1803 // ARB path (any Geforce, any Radeon)
1804 qboolean doambient = r_shadow_rtlight->ambientscale > 0;
1805 qboolean dodiffuse = r_shadow_rtlight->diffusescale > 0;
1806 qboolean dospecular = specularscale > 0;
1807 if (!doambient && !dodiffuse && !dospecular)
1809 RSurf_PrepareVerticesForBatch(true, true, numsurfaces, surfacelist);
1810 R_Mesh_ColorPointer(NULL);
1812 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorbase, basetexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1814 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorbase, basetexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1818 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorpants, pantstexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1820 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorpants, pantstexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1825 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1827 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1830 R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(numsurfaces, surfacelist, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale);
1833 void R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(const model_t *model, int numsurfaces, msurface_t **surfacelist, vec3_t diffusecolor2, vec3_t ambientcolor2)
1835 int surfacelistindex;
1837 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1839 const msurface_t *surface = surfacelist[surfacelistindex];
1840 R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(surface, diffusecolor2, ambientcolor2);
1842 for (renders = 0;renders < 64;renders++)
1848 int newnumtriangles;
1850 int newelements[3072];
1854 newnumtriangles = 0;
1856 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1858 const msurface_t *surface = surfacelist[surfacelistindex];
1859 const int *elements = rsurface_model->surfmesh.data_element3i + surface->num_firsttriangle * 3;
1861 // due to low fillrate on the cards this vertex lighting path is
1862 // designed for, we manually cull all triangles that do not
1863 // contain a lit vertex
1864 // this builds batches of triangles from multiple surfaces and
1865 // renders them at once
1866 for (i = 0, e = elements;i < surface->num_triangles;i++, e += 3)
1868 if (VectorLength2(rsurface_array_color4f + e[0] * 4) + VectorLength2(rsurface_array_color4f + e[1] * 4) + VectorLength2(rsurface_array_color4f + e[2] * 4) >= 0.01)
1870 if (newnumtriangles)
1872 firstvertex = min(firstvertex, e[0]);
1873 lastvertex = max(lastvertex, e[0]);
1880 firstvertex = min(firstvertex, e[1]);
1881 lastvertex = max(lastvertex, e[1]);
1882 firstvertex = min(firstvertex, e[2]);
1883 lastvertex = max(lastvertex, e[2]);
1889 if (newnumtriangles >= 1024)
1891 GL_LockArrays(firstvertex, lastvertex - firstvertex + 1);
1892 R_Mesh_Draw(firstvertex, lastvertex - firstvertex + 1, newnumtriangles, newelements);
1893 newnumtriangles = 0;
1900 if (newnumtriangles >= 1)
1902 GL_LockArrays(firstvertex, lastvertex - firstvertex + 1);
1903 R_Mesh_Draw(firstvertex, lastvertex - firstvertex + 1, newnumtriangles, newelements);
1906 GL_LockArrays(0, 0);
1907 // if we couldn't find any lit triangles, exit early
1910 // now reduce the intensity for the next overbright pass
1911 // we have to clamp to 0 here incase the drivers have improper
1912 // handling of negative colors
1913 // (some old drivers even have improper handling of >1 color)
1915 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1919 const msurface_t *surface = surfacelist[surfacelistindex];
1920 for (i = 0, c = rsurface_array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
1922 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
1924 c[0] = max(0, c[0] - 1);
1925 c[1] = max(0, c[1] - 1);
1926 c[2] = max(0, c[2] - 1);
1939 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)
1941 // OpenGL 1.1 path (anything)
1942 model_t *model = rsurface_entity->model;
1943 float ambientcolorbase[3], diffusecolorbase[3];
1944 float ambientcolorpants[3], diffusecolorpants[3];
1945 float ambientcolorshirt[3], diffusecolorshirt[3];
1947 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorbase);
1948 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorbase);
1949 VectorScale(lightcolorpants, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorpants);
1950 VectorScale(lightcolorpants, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorpants);
1951 VectorScale(lightcolorshirt, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorshirt);
1952 VectorScale(lightcolorshirt, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorshirt);
1953 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1954 R_Mesh_ColorPointer(rsurface_array_color4f);
1955 memset(&m, 0, sizeof(m));
1956 m.tex[0] = R_GetTexture(basetexture);
1957 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1958 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1959 if (r_textureunits.integer >= 2)
1962 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1963 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1964 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1965 if (r_textureunits.integer >= 3)
1967 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
1968 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1969 m.texmatrix[2] = r_shadow_entitytoattenuationz;
1970 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1973 R_Mesh_TextureState(&m);
1974 RSurf_PrepareVerticesForBatch(true, false, numsurfaces, surfacelist);
1975 R_Mesh_TexBind(0, R_GetTexture(basetexture));
1976 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorbase, ambientcolorbase);
1979 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
1980 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorpants, ambientcolorpants);
1984 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
1985 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorshirt, ambientcolorshirt);
1989 void R_Shadow_RenderSurfacesLighting(int numsurfaces, msurface_t **surfacelist)
1991 // FIXME: support MATERIALFLAG_NODEPTHTEST
1992 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
1993 // calculate colors to render this texture with
1994 lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * rsurface_entity->colormod[0] * rsurface_texture->currentalpha;
1995 lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * rsurface_entity->colormod[1] * rsurface_texture->currentalpha;
1996 lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * rsurface_entity->colormod[2] * rsurface_texture->currentalpha;
1997 if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) + (r_shadow_rtlight->specularscale * rsurface_texture->specularscale) * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
1999 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
2000 GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
2001 if (rsurface_texture->colormapping)
2003 qboolean dopants = rsurface_texture->currentskinframe->pants != NULL && VectorLength2(rsurface_entity->colormap_pantscolor) >= (1.0f / 1048576.0f);
2004 qboolean doshirt = rsurface_texture->currentskinframe->shirt != NULL && VectorLength2(rsurface_entity->colormap_shirtcolor) >= (1.0f / 1048576.0f);
2007 lightcolorpants[0] = lightcolorbase[0] * rsurface_entity->colormap_pantscolor[0];
2008 lightcolorpants[1] = lightcolorbase[1] * rsurface_entity->colormap_pantscolor[1];
2009 lightcolorpants[2] = lightcolorbase[2] * rsurface_entity->colormap_pantscolor[2];
2012 VectorClear(lightcolorpants);
2015 lightcolorshirt[0] = lightcolorbase[0] * rsurface_entity->colormap_shirtcolor[0];
2016 lightcolorshirt[1] = lightcolorbase[1] * rsurface_entity->colormap_shirtcolor[1];
2017 lightcolorshirt[2] = lightcolorbase[2] * rsurface_entity->colormap_shirtcolor[2];
2020 VectorClear(lightcolorshirt);
2021 switch (r_shadow_rendermode)
2023 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2024 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2025 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);
2027 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2028 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);
2030 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2031 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);
2033 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2034 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);
2037 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2043 switch (r_shadow_rendermode)
2045 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2046 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2047 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);
2049 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2050 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);
2052 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2053 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);
2055 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2056 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);
2059 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2065 void R_RTLight_Update(dlight_t *light, int isstatic)
2068 rtlight_t *rtlight = &light->rtlight;
2069 R_RTLight_Uncompile(rtlight);
2070 memset(rtlight, 0, sizeof(*rtlight));
2072 VectorCopy(light->origin, rtlight->shadoworigin);
2073 VectorCopy(light->color, rtlight->color);
2074 rtlight->radius = light->radius;
2075 //rtlight->cullradius = rtlight->radius;
2076 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2077 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2078 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2079 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2080 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2081 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2082 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2083 rtlight->cubemapname[0] = 0;
2084 if (light->cubemapname[0])
2085 strlcpy(rtlight->cubemapname, light->cubemapname, sizeof(rtlight->cubemapname));
2086 else if (light->cubemapnum > 0)
2087 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2088 rtlight->shadow = light->shadow;
2089 rtlight->corona = light->corona;
2090 rtlight->style = light->style;
2091 rtlight->isstatic = isstatic;
2092 rtlight->coronasizescale = light->coronasizescale;
2093 rtlight->ambientscale = light->ambientscale;
2094 rtlight->diffusescale = light->diffusescale;
2095 rtlight->specularscale = light->specularscale;
2096 rtlight->flags = light->flags;
2097 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2098 // this has to scale both rotate and translate because this is an already
2099 // inverted matrix (it transforms from world to light space, not the other
2101 scale = 1.0 / rtlight->radius;
2102 Matrix4x4_Scale(&rtlight->matrix_worldtolight, scale, scale);
2105 // compiles rtlight geometry
2106 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2107 void R_RTLight_Compile(rtlight_t *rtlight)
2109 int shadowmeshes, shadowtris, numleafs, numleafpvsbytes, numsurfaces;
2110 entity_render_t *ent = r_refdef.worldentity;
2111 model_t *model = r_refdef.worldmodel;
2112 unsigned char *data;
2114 // compile the light
2115 rtlight->compiled = true;
2116 rtlight->static_numleafs = 0;
2117 rtlight->static_numleafpvsbytes = 0;
2118 rtlight->static_leaflist = NULL;
2119 rtlight->static_leafpvs = NULL;
2120 rtlight->static_numsurfaces = 0;
2121 rtlight->static_surfacelist = NULL;
2122 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2123 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2124 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2125 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2126 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2127 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2129 if (model && model->GetLightInfo)
2131 // this variable must be set for the CompileShadowVolume code
2132 r_shadow_compilingrtlight = rtlight;
2133 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
2134 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);
2135 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2136 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2137 rtlight->static_numleafs = numleafs;
2138 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2139 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2140 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2141 rtlight->static_numsurfaces = numsurfaces;
2142 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2144 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2145 if (numleafpvsbytes)
2146 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2148 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2149 if (model->CompileShadowVolume && rtlight->shadow)
2150 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2151 // now we're done compiling the rtlight
2152 r_shadow_compilingrtlight = NULL;
2156 // use smallest available cullradius - box radius or light radius
2157 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2158 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2162 if (rtlight->static_meshchain_shadow)
2165 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2168 shadowtris += mesh->numtriangles;
2172 if (developer.integer >= 10)
2173 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);
2176 void R_RTLight_Uncompile(rtlight_t *rtlight)
2178 if (rtlight->compiled)
2180 if (rtlight->static_meshchain_shadow)
2181 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2182 rtlight->static_meshchain_shadow = NULL;
2183 // these allocations are grouped
2184 if (rtlight->static_leaflist)
2185 Mem_Free(rtlight->static_leaflist);
2186 rtlight->static_numleafs = 0;
2187 rtlight->static_numleafpvsbytes = 0;
2188 rtlight->static_leaflist = NULL;
2189 rtlight->static_leafpvs = NULL;
2190 rtlight->static_numsurfaces = 0;
2191 rtlight->static_surfacelist = NULL;
2192 rtlight->compiled = false;
2196 void R_Shadow_UncompileWorldLights(void)
2199 for (light = r_shadow_worldlightchain;light;light = light->next)
2200 R_RTLight_Uncompile(&light->rtlight);
2203 void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfacelist)
2205 model_t *model = ent->model;
2206 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2207 vec_t relativeshadowradius;
2208 if (ent == r_refdef.worldentity)
2210 if (r_shadow_rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2213 R_Mesh_Matrix(&ent->matrix);
2215 for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2217 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2218 R_Mesh_VertexPointer(mesh->vertex3f);
2219 GL_LockArrays(0, mesh->numverts);
2220 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2222 // decrement stencil if backface is behind depthbuffer
2223 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
2224 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2225 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2226 // increment stencil if frontface is behind depthbuffer
2227 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2228 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2230 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2231 GL_LockArrays(0, 0);
2235 else if (numsurfaces)
2237 R_Mesh_Matrix(&ent->matrix);
2238 model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, NULL, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs);
2243 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, relativeshadoworigin);
2244 relativeshadowradius = r_shadow_rtlight->radius / ent->scale;
2245 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2246 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2247 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2248 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2249 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2250 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2251 R_Mesh_Matrix(&ent->matrix);
2252 model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, model->nummodelsurfaces, model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2256 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2258 // set up properties for rendering light onto this entity
2259 RSurf_ActiveEntity(ent, true, true);
2260 Matrix4x4_Concat(&r_shadow_entitytolight, &r_shadow_rtlight->matrix_worldtolight, &ent->matrix);
2261 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2262 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2263 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2264 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2265 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2268 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2270 model_t *model = ent->model;
2271 if (!model->DrawLight)
2273 R_Shadow_SetupEntityLight(ent);
2274 if (ent == r_refdef.worldentity)
2275 model->DrawLight(ent, numsurfaces, surfacelist);
2277 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist);
2280 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2284 int numleafs, numsurfaces;
2285 int *leaflist, *surfacelist;
2286 unsigned char *leafpvs;
2287 int numlightentities;
2288 int numshadowentities;
2289 entity_render_t *lightentities[MAX_EDICTS];
2290 entity_render_t *shadowentities[MAX_EDICTS];
2292 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2293 // skip lights that are basically invisible (color 0 0 0)
2294 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2297 // loading is done before visibility checks because loading should happen
2298 // all at once at the start of a level, not when it stalls gameplay.
2299 // (especially important to benchmarks)
2301 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2302 R_RTLight_Compile(rtlight);
2304 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2306 // look up the light style value at this time
2307 f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2308 VectorScale(rtlight->color, f, rtlight->currentcolor);
2310 if (rtlight->selected)
2312 f = 2 + sin(realtime * M_PI * 4.0);
2313 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2317 // if lightstyle is currently off, don't draw the light
2318 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2321 // if the light box is offscreen, skip it
2322 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2325 VectorCopy(rtlight->cullmins, r_shadow_rtlight_cullmins);
2326 VectorCopy(rtlight->cullmaxs, r_shadow_rtlight_cullmaxs);
2328 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2330 // compiled light, world available and can receive realtime lighting
2331 // retrieve leaf information
2332 numleafs = rtlight->static_numleafs;
2333 leaflist = rtlight->static_leaflist;
2334 leafpvs = rtlight->static_leafpvs;
2335 numsurfaces = rtlight->static_numsurfaces;
2336 surfacelist = rtlight->static_surfacelist;
2338 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2340 // dynamic light, world available and can receive realtime lighting
2341 // calculate lit surfaces and leafs
2342 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces);
2343 r_refdef.worldmodel->GetLightInfo(r_refdef.worldentity, rtlight->shadoworigin, rtlight->radius, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
2344 leaflist = r_shadow_buffer_leaflist;
2345 leafpvs = r_shadow_buffer_leafpvs;
2346 surfacelist = r_shadow_buffer_surfacelist;
2347 // if the reduced leaf bounds are offscreen, skip it
2348 if (R_CullBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2360 // check if light is illuminating any visible leafs
2363 for (i = 0;i < numleafs;i++)
2364 if (r_viewcache.world_leafvisible[leaflist[i]])
2369 // set up a scissor rectangle for this light
2370 if (R_Shadow_ScissorForBBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2373 // make a list of lit entities and shadow casting entities
2374 numlightentities = 0;
2375 numshadowentities = 0;
2376 // don't count the world unless some surfaces are actually lit
2379 lightentities[numlightentities++] = r_refdef.worldentity;
2380 shadowentities[numshadowentities++] = r_refdef.worldentity;
2382 // add dynamic entities that are lit by the light
2383 if (r_drawentities.integer)
2385 for (i = 0;i < r_refdef.numentities;i++)
2388 entity_render_t *ent = r_refdef.entities[i];
2389 if (BoxesOverlap(ent->mins, ent->maxs, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs)
2390 && (model = ent->model)
2391 && !(ent->flags & RENDER_TRANSPARENT)
2392 && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2394 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2396 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2397 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2398 shadowentities[numshadowentities++] = ent;
2399 if (r_viewcache.entityvisible[i] && (ent->flags & RENDER_LIGHT) && model->DrawLight)
2400 lightentities[numlightentities++] = ent;
2405 // return if there's nothing at all to light
2406 if (!numlightentities)
2409 // don't let sound skip if going slow
2410 if (r_refdef.extraupdate)
2413 // make this the active rtlight for rendering purposes
2414 R_Shadow_RenderMode_ActiveLight(rtlight);
2415 // count this light in the r_speeds
2416 r_refdef.stats.lights++;
2419 if (numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2421 // draw stencil shadow volumes to mask off pixels that are in shadow
2422 // so that they won't receive lighting
2426 R_Shadow_RenderMode_StencilShadowVolumes();
2427 for (i = 0;i < numshadowentities;i++)
2428 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2431 // optionally draw visible shape of the shadow volumes
2432 // for performance analysis by level designers
2433 if (r_showshadowvolumes.integer)
2435 R_Shadow_RenderMode_VisibleShadowVolumes();
2436 for (i = 0;i < numshadowentities;i++)
2437 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2441 if (numlightentities)
2443 // draw lighting in the unmasked areas
2444 R_Shadow_RenderMode_Lighting(usestencil, false);
2445 for (i = 0;i < numlightentities;i++)
2446 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2448 // optionally draw the illuminated areas
2449 // for performance analysis by level designers
2450 if (r_showlighting.integer)
2452 R_Shadow_RenderMode_VisibleLighting(usestencil && !r_showdisabledepthtest.integer, false);
2453 for (i = 0;i < numlightentities;i++)
2454 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2459 void R_ShadowVolumeLighting(qboolean visible)
2464 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2465 R_Shadow_EditLights_Reload_f();
2467 R_Shadow_RenderMode_Begin();
2469 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2470 if (r_shadow_debuglight.integer >= 0)
2472 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2473 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2474 R_DrawRTLight(&light->rtlight, visible);
2477 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2478 if (light->flags & flag)
2479 R_DrawRTLight(&light->rtlight, visible);
2480 if (r_refdef.rtdlight)
2481 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
2482 R_DrawRTLight(&r_refdef.lights[lnum]->rtlight, visible);
2484 R_Shadow_RenderMode_End();
2487 extern void R_SetupView(const matrix4x4_t *matrix);
2488 extern cvar_t r_shadows_throwdistance;
2489 void R_DrawModelShadows(void)
2492 float relativethrowdistance;
2493 entity_render_t *ent;
2494 vec3_t relativelightorigin;
2495 vec3_t relativelightdirection;
2496 vec3_t relativeshadowmins, relativeshadowmaxs;
2499 if (!r_drawentities.integer || !gl_stencil)
2503 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2505 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2507 if (gl_ext_separatestencil.integer)
2508 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
2509 else if (gl_ext_stenciltwoside.integer)
2510 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
2512 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
2514 R_Shadow_RenderMode_StencilShadowVolumes();
2516 for (i = 0;i < r_refdef.numentities;i++)
2518 ent = r_refdef.entities[i];
2519 // cast shadows from anything that is not a submodel of the map
2520 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
2522 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
2523 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
2524 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
2525 VectorNegate(ent->modellight_lightdir, relativelightdirection);
2526 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
2527 R_Mesh_Matrix(&ent->matrix);
2528 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2532 // not really the right mode, but this will disable any silly stencil features
2533 R_Shadow_RenderMode_VisibleLighting(true, true);
2535 // vertex coordinates for a quad that covers the screen exactly
2536 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
2537 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
2538 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
2539 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
2541 // set up ortho view for rendering this pass
2542 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
2543 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2544 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2545 GL_ScissorTest(true);
2546 R_Mesh_Matrix(&identitymatrix);
2547 R_Mesh_ResetTextureState();
2548 R_Mesh_VertexPointer(vertex3f);
2549 R_Mesh_ColorPointer(NULL);
2551 // set up a 50% darkening blend on shadowed areas
2552 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2553 GL_DepthTest(false);
2554 GL_DepthMask(false);
2555 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2556 GL_Color(0, 0, 0, 0.5);
2557 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2558 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
2559 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2560 qglStencilMask(~0);CHECKGLERROR
2561 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
2562 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
2564 // apply the blend to the shadowed areas
2565 R_Mesh_Draw(0, 4, 2, polygonelements);
2567 // restoring the perspective view is done by R_RenderScene
2568 //R_SetupView(&r_view.matrix);
2570 // restore other state to normal
2571 R_Shadow_RenderMode_End();
2575 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2576 typedef struct suffixinfo_s
2579 qboolean flipx, flipy, flipdiagonal;
2582 static suffixinfo_t suffix[3][6] =
2585 {"px", false, false, false},
2586 {"nx", false, false, false},
2587 {"py", false, false, false},
2588 {"ny", false, false, false},
2589 {"pz", false, false, false},
2590 {"nz", false, false, false}
2593 {"posx", false, false, false},
2594 {"negx", false, false, false},
2595 {"posy", false, false, false},
2596 {"negy", false, false, false},
2597 {"posz", false, false, false},
2598 {"negz", false, false, false}
2601 {"rt", true, false, true},
2602 {"lf", false, true, true},
2603 {"ft", true, true, false},
2604 {"bk", false, false, false},
2605 {"up", true, false, true},
2606 {"dn", true, false, true}
2610 static int componentorder[4] = {0, 1, 2, 3};
2612 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2614 int i, j, cubemapsize;
2615 unsigned char *cubemappixels, *image_rgba;
2616 rtexture_t *cubemaptexture;
2618 // must start 0 so the first loadimagepixels has no requested width/height
2620 cubemappixels = NULL;
2621 cubemaptexture = NULL;
2622 // keep trying different suffix groups (posx, px, rt) until one loads
2623 for (j = 0;j < 3 && !cubemappixels;j++)
2625 // load the 6 images in the suffix group
2626 for (i = 0;i < 6;i++)
2628 // generate an image name based on the base and and suffix
2629 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2631 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2633 // an image loaded, make sure width and height are equal
2634 if (image_width == image_height)
2636 // if this is the first image to load successfully, allocate the cubemap memory
2637 if (!cubemappixels && image_width >= 1)
2639 cubemapsize = image_width;
2640 // note this clears to black, so unavailable sides are black
2641 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2643 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2645 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);
2648 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2650 Mem_Free(image_rgba);
2654 // if a cubemap loaded, upload it
2657 if (!r_shadow_filters_texturepool)
2658 r_shadow_filters_texturepool = R_AllocTexturePool();
2659 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2660 Mem_Free(cubemappixels);
2664 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2665 for (j = 0;j < 3;j++)
2666 for (i = 0;i < 6;i++)
2667 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2668 Con_Print(" and was unable to find any of them.\n");
2670 return cubemaptexture;
2673 rtexture_t *R_Shadow_Cubemap(const char *basename)
2676 for (i = 0;i < numcubemaps;i++)
2677 if (!strcasecmp(cubemaps[i].basename, basename))
2678 return cubemaps[i].texture;
2679 if (i >= MAX_CUBEMAPS)
2680 return r_texture_whitecube;
2682 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
2683 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2684 if (!cubemaps[i].texture)
2685 cubemaps[i].texture = r_texture_whitecube;
2686 return cubemaps[i].texture;
2689 void R_Shadow_FreeCubemaps(void)
2692 R_FreeTexturePool(&r_shadow_filters_texturepool);
2695 dlight_t *R_Shadow_NewWorldLight(void)
2698 light = (dlight_t *)Mem_Alloc(r_main_mempool, sizeof(dlight_t));
2699 light->next = r_shadow_worldlightchain;
2700 r_shadow_worldlightchain = light;
2704 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)
2706 VectorCopy(origin, light->origin);
2707 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
2708 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
2709 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
2710 light->color[0] = max(color[0], 0);
2711 light->color[1] = max(color[1], 0);
2712 light->color[2] = max(color[2], 0);
2713 light->radius = max(radius, 0);
2714 light->style = style;
2715 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2717 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2720 light->shadow = shadowenable;
2721 light->corona = corona;
2724 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
2725 light->coronasizescale = coronasizescale;
2726 light->ambientscale = ambientscale;
2727 light->diffusescale = diffusescale;
2728 light->specularscale = specularscale;
2729 light->flags = flags;
2730 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2732 R_RTLight_Update(light, true);
2735 void R_Shadow_FreeWorldLight(dlight_t *light)
2737 dlight_t **lightpointer;
2738 R_RTLight_Uncompile(&light->rtlight);
2739 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2740 if (*lightpointer != light)
2741 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
2742 *lightpointer = light->next;
2746 void R_Shadow_ClearWorldLights(void)
2748 while (r_shadow_worldlightchain)
2749 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2750 r_shadow_selectedlight = NULL;
2751 R_Shadow_FreeCubemaps();
2754 void R_Shadow_SelectLight(dlight_t *light)
2756 if (r_shadow_selectedlight)
2757 r_shadow_selectedlight->selected = false;
2758 r_shadow_selectedlight = light;
2759 if (r_shadow_selectedlight)
2760 r_shadow_selectedlight->selected = true;
2763 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2765 // this is never batched (there can be only one)
2766 float scale = r_editlights_cursorgrid.value * 0.5f;
2767 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);
2770 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2772 // this is never batched (due to the ent parameter changing every time)
2773 // so numsurfaces == 1 and surfacelist[0] == lightnumber
2775 const dlight_t *light = (dlight_t *)ent;
2777 if (light->selected)
2778 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2781 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);
2784 void R_Shadow_DrawLightSprites(void)
2789 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
2790 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 1+(i % 5), &light->rtlight);
2791 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
2794 void R_Shadow_SelectLightInView(void)
2796 float bestrating, rating, temp[3];
2797 dlight_t *best, *light;
2800 for (light = r_shadow_worldlightchain;light;light = light->next)
2802 VectorSubtract(light->origin, r_view.origin, temp);
2803 rating = (DotProduct(temp, r_view.forward) / sqrt(DotProduct(temp, temp)));
2806 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2807 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_view.origin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
2809 bestrating = rating;
2814 R_Shadow_SelectLight(best);
2817 void R_Shadow_LoadWorldLights(void)
2819 int n, a, style, shadow, flags;
2820 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
2821 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
2822 if (r_refdef.worldmodel == NULL)
2824 Con_Print("No map loaded.\n");
2827 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2828 strlcat (name, ".rtlights", sizeof (name));
2829 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
2839 for (;COM_Parse(t, true) && strcmp(
2840 if (COM_Parse(t, true))
2842 if (com_token[0] == '!')
2845 origin[0] = atof(com_token+1);
2848 origin[0] = atof(com_token);
2853 while (*s && *s != '\n' && *s != '\r')
2859 // check for modifier flags
2866 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);
2869 flags = LIGHTFLAG_REALTIMEMODE;
2877 coronasizescale = 0.25f;
2879 VectorClear(angles);
2882 if (a < 9 || !strcmp(cubemapname, "\"\""))
2884 // remove quotes on cubemapname
2885 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
2888 namelen = strlen(cubemapname) - 2;
2889 memmove(cubemapname, cubemapname + 1, namelen);
2890 cubemapname[namelen] = '\0';
2894 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);
2897 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
2905 Con_Printf("invalid rtlights file \"%s\"\n", name);
2906 Mem_Free(lightsstring);
2910 void R_Shadow_SaveWorldLights(void)
2913 size_t bufchars, bufmaxchars;
2915 char name[MAX_QPATH];
2916 char line[MAX_INPUTLINE];
2917 if (!r_shadow_worldlightchain)
2919 if (r_refdef.worldmodel == NULL)
2921 Con_Print("No map loaded.\n");
2924 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2925 strlcat (name, ".rtlights", sizeof (name));
2926 bufchars = bufmaxchars = 0;
2928 for (light = r_shadow_worldlightchain;light;light = light->next)
2930 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
2931 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);
2932 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
2933 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]);
2935 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);
2936 if (bufchars + strlen(line) > bufmaxchars)
2938 bufmaxchars = bufchars + strlen(line) + 2048;
2940 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
2944 memcpy(buf, oldbuf, bufchars);
2950 memcpy(buf + bufchars, line, strlen(line));
2951 bufchars += strlen(line);
2955 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
2960 void R_Shadow_LoadLightsFile(void)
2963 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
2964 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2965 if (r_refdef.worldmodel == NULL)
2967 Con_Print("No map loaded.\n");
2970 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2971 strlcat (name, ".lights", sizeof (name));
2972 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
2980 while (*s && *s != '\n' && *s != '\r')
2986 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);
2990 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);
2993 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2994 radius = bound(15, radius, 4096);
2995 VectorScale(color, (2.0f / (8388608.0f)), color);
2996 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3004 Con_Printf("invalid lights file \"%s\"\n", name);
3005 Mem_Free(lightsstring);
3009 // tyrlite/hmap2 light types in the delay field
3010 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3012 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3014 int entnum, style, islight, skin, pflags, effects, type, n;
3017 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3018 char key[256], value[MAX_INPUTLINE];
3020 if (r_refdef.worldmodel == NULL)
3022 Con_Print("No map loaded.\n");
3025 // try to load a .ent file first
3026 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3027 strlcat (key, ".ent", sizeof (key));
3028 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3029 // and if that is not found, fall back to the bsp file entity string
3031 data = r_refdef.worldmodel->brush.entities;
3034 for (entnum = 0;COM_ParseTokenConsole(&data) && com_token[0] == '{';entnum++)
3036 type = LIGHTTYPE_MINUSX;
3037 origin[0] = origin[1] = origin[2] = 0;
3038 originhack[0] = originhack[1] = originhack[2] = 0;
3039 angles[0] = angles[1] = angles[2] = 0;
3040 color[0] = color[1] = color[2] = 1;
3041 light[0] = light[1] = light[2] = 1;light[3] = 300;
3042 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3052 if (!COM_ParseTokenConsole(&data))
3054 if (com_token[0] == '}')
3055 break; // end of entity
3056 if (com_token[0] == '_')
3057 strlcpy(key, com_token + 1, sizeof(key));
3059 strlcpy(key, com_token, sizeof(key));
3060 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3061 key[strlen(key)-1] = 0;
3062 if (!COM_ParseTokenConsole(&data))
3064 strlcpy(value, com_token, sizeof(value));
3066 // now that we have the key pair worked out...
3067 if (!strcmp("light", key))
3069 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3073 light[0] = vec[0] * (1.0f / 256.0f);
3074 light[1] = vec[0] * (1.0f / 256.0f);
3075 light[2] = vec[0] * (1.0f / 256.0f);
3081 light[0] = vec[0] * (1.0f / 255.0f);
3082 light[1] = vec[1] * (1.0f / 255.0f);
3083 light[2] = vec[2] * (1.0f / 255.0f);
3087 else if (!strcmp("delay", key))
3089 else if (!strcmp("origin", key))
3090 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3091 else if (!strcmp("angle", key))
3092 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3093 else if (!strcmp("angles", key))
3094 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3095 else if (!strcmp("color", key))
3096 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3097 else if (!strcmp("wait", key))
3098 fadescale = atof(value);
3099 else if (!strcmp("classname", key))
3101 if (!strncmp(value, "light", 5))
3104 if (!strcmp(value, "light_fluoro"))
3109 overridecolor[0] = 1;
3110 overridecolor[1] = 1;
3111 overridecolor[2] = 1;
3113 if (!strcmp(value, "light_fluorospark"))
3118 overridecolor[0] = 1;
3119 overridecolor[1] = 1;
3120 overridecolor[2] = 1;
3122 if (!strcmp(value, "light_globe"))
3127 overridecolor[0] = 1;
3128 overridecolor[1] = 0.8;
3129 overridecolor[2] = 0.4;
3131 if (!strcmp(value, "light_flame_large_yellow"))
3136 overridecolor[0] = 1;
3137 overridecolor[1] = 0.5;
3138 overridecolor[2] = 0.1;
3140 if (!strcmp(value, "light_flame_small_yellow"))
3145 overridecolor[0] = 1;
3146 overridecolor[1] = 0.5;
3147 overridecolor[2] = 0.1;
3149 if (!strcmp(value, "light_torch_small_white"))
3154 overridecolor[0] = 1;
3155 overridecolor[1] = 0.5;
3156 overridecolor[2] = 0.1;
3158 if (!strcmp(value, "light_torch_small_walltorch"))
3163 overridecolor[0] = 1;
3164 overridecolor[1] = 0.5;
3165 overridecolor[2] = 0.1;
3169 else if (!strcmp("style", key))
3170 style = atoi(value);
3171 else if (!strcmp("skin", key))
3172 skin = (int)atof(value);
3173 else if (!strcmp("pflags", key))
3174 pflags = (int)atof(value);
3175 else if (!strcmp("effects", key))
3176 effects = (int)atof(value);
3177 else if (r_refdef.worldmodel->type == mod_brushq3)
3179 if (!strcmp("scale", key))
3180 lightscale = atof(value);
3181 if (!strcmp("fade", key))
3182 fadescale = atof(value);
3187 if (lightscale <= 0)
3191 if (color[0] == color[1] && color[0] == color[2])
3193 color[0] *= overridecolor[0];
3194 color[1] *= overridecolor[1];
3195 color[2] *= overridecolor[2];
3197 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3198 color[0] = color[0] * light[0];
3199 color[1] = color[1] * light[1];
3200 color[2] = color[2] * light[2];
3203 case LIGHTTYPE_MINUSX:
3205 case LIGHTTYPE_RECIPX:
3207 VectorScale(color, (1.0f / 16.0f), color);
3209 case LIGHTTYPE_RECIPXX:
3211 VectorScale(color, (1.0f / 16.0f), color);
3214 case LIGHTTYPE_NONE:
3218 case LIGHTTYPE_MINUSXX:
3221 VectorAdd(origin, originhack, origin);
3223 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);
3226 Mem_Free(entfiledata);
3230 void R_Shadow_SetCursorLocationForView(void)
3233 vec3_t dest, endpos;
3235 VectorMA(r_view.origin, r_editlights_cursordistance.value, r_view.forward, dest);
3236 trace = CL_TraceBox(r_view.origin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3237 if (trace.fraction < 1)
3239 dist = trace.fraction * r_editlights_cursordistance.value;
3240 push = r_editlights_cursorpushback.value;
3244 VectorMA(trace.endpos, push, r_view.forward, endpos);
3245 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3249 VectorClear( endpos );
3251 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3252 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3253 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3256 void R_Shadow_UpdateWorldLightSelection(void)
3258 if (r_editlights.integer)
3260 R_Shadow_SetCursorLocationForView();
3261 R_Shadow_SelectLightInView();
3262 R_Shadow_DrawLightSprites();
3265 R_Shadow_SelectLight(NULL);
3268 void R_Shadow_EditLights_Clear_f(void)
3270 R_Shadow_ClearWorldLights();
3273 void R_Shadow_EditLights_Reload_f(void)
3275 if (!r_refdef.worldmodel)
3277 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3278 R_Shadow_ClearWorldLights();
3279 R_Shadow_LoadWorldLights();
3280 if (r_shadow_worldlightchain == NULL)
3282 R_Shadow_LoadLightsFile();
3283 if (r_shadow_worldlightchain == NULL)
3284 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3288 void R_Shadow_EditLights_Save_f(void)
3290 if (!r_refdef.worldmodel)
3292 R_Shadow_SaveWorldLights();
3295 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3297 R_Shadow_ClearWorldLights();
3298 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3301 void R_Shadow_EditLights_ImportLightsFile_f(void)
3303 R_Shadow_ClearWorldLights();
3304 R_Shadow_LoadLightsFile();
3307 void R_Shadow_EditLights_Spawn_f(void)
3310 if (!r_editlights.integer)
3312 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3315 if (Cmd_Argc() != 1)
3317 Con_Print("r_editlights_spawn does not take parameters\n");
3320 color[0] = color[1] = color[2] = 1;
3321 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3324 void R_Shadow_EditLights_Edit_f(void)
3326 vec3_t origin, angles, color;
3327 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3328 int style, shadows, flags, normalmode, realtimemode;
3329 char cubemapname[MAX_INPUTLINE];
3330 if (!r_editlights.integer)
3332 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3335 if (!r_shadow_selectedlight)
3337 Con_Print("No selected light.\n");
3340 VectorCopy(r_shadow_selectedlight->origin, origin);
3341 VectorCopy(r_shadow_selectedlight->angles, angles);
3342 VectorCopy(r_shadow_selectedlight->color, color);
3343 radius = r_shadow_selectedlight->radius;
3344 style = r_shadow_selectedlight->style;
3345 if (r_shadow_selectedlight->cubemapname)
3346 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3349 shadows = r_shadow_selectedlight->shadow;
3350 corona = r_shadow_selectedlight->corona;
3351 coronasizescale = r_shadow_selectedlight->coronasizescale;
3352 ambientscale = r_shadow_selectedlight->ambientscale;
3353 diffusescale = r_shadow_selectedlight->diffusescale;
3354 specularscale = r_shadow_selectedlight->specularscale;
3355 flags = r_shadow_selectedlight->flags;
3356 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3357 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3358 if (!strcmp(Cmd_Argv(1), "origin"))
3360 if (Cmd_Argc() != 5)
3362 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3365 origin[0] = atof(Cmd_Argv(2));
3366 origin[1] = atof(Cmd_Argv(3));
3367 origin[2] = atof(Cmd_Argv(4));
3369 else if (!strcmp(Cmd_Argv(1), "originx"))
3371 if (Cmd_Argc() != 3)
3373 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3376 origin[0] = atof(Cmd_Argv(2));
3378 else if (!strcmp(Cmd_Argv(1), "originy"))
3380 if (Cmd_Argc() != 3)
3382 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3385 origin[1] = atof(Cmd_Argv(2));
3387 else if (!strcmp(Cmd_Argv(1), "originz"))
3389 if (Cmd_Argc() != 3)
3391 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3394 origin[2] = atof(Cmd_Argv(2));
3396 else if (!strcmp(Cmd_Argv(1), "move"))
3398 if (Cmd_Argc() != 5)
3400 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3403 origin[0] += atof(Cmd_Argv(2));
3404 origin[1] += atof(Cmd_Argv(3));
3405 origin[2] += atof(Cmd_Argv(4));
3407 else if (!strcmp(Cmd_Argv(1), "movex"))
3409 if (Cmd_Argc() != 3)
3411 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3414 origin[0] += atof(Cmd_Argv(2));
3416 else if (!strcmp(Cmd_Argv(1), "movey"))
3418 if (Cmd_Argc() != 3)
3420 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3423 origin[1] += atof(Cmd_Argv(2));
3425 else if (!strcmp(Cmd_Argv(1), "movez"))
3427 if (Cmd_Argc() != 3)
3429 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3432 origin[2] += atof(Cmd_Argv(2));
3434 else if (!strcmp(Cmd_Argv(1), "angles"))
3436 if (Cmd_Argc() != 5)
3438 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3441 angles[0] = atof(Cmd_Argv(2));
3442 angles[1] = atof(Cmd_Argv(3));
3443 angles[2] = atof(Cmd_Argv(4));
3445 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3447 if (Cmd_Argc() != 3)
3449 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3452 angles[0] = atof(Cmd_Argv(2));
3454 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3456 if (Cmd_Argc() != 3)
3458 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3461 angles[1] = atof(Cmd_Argv(2));
3463 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3465 if (Cmd_Argc() != 3)
3467 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3470 angles[2] = atof(Cmd_Argv(2));
3472 else if (!strcmp(Cmd_Argv(1), "color"))
3474 if (Cmd_Argc() != 5)
3476 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3479 color[0] = atof(Cmd_Argv(2));
3480 color[1] = atof(Cmd_Argv(3));
3481 color[2] = atof(Cmd_Argv(4));
3483 else if (!strcmp(Cmd_Argv(1), "radius"))
3485 if (Cmd_Argc() != 3)
3487 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3490 radius = atof(Cmd_Argv(2));
3492 else if (!strcmp(Cmd_Argv(1), "colorscale"))
3494 if (Cmd_Argc() == 3)
3496 double scale = atof(Cmd_Argv(2));
3503 if (Cmd_Argc() != 5)
3505 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
3508 color[0] *= atof(Cmd_Argv(2));
3509 color[1] *= atof(Cmd_Argv(3));
3510 color[2] *= atof(Cmd_Argv(4));
3513 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
3515 if (Cmd_Argc() != 3)
3517 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3520 radius *= atof(Cmd_Argv(2));
3522 else if (!strcmp(Cmd_Argv(1), "style"))
3524 if (Cmd_Argc() != 3)
3526 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3529 style = atoi(Cmd_Argv(2));
3531 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3535 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3538 if (Cmd_Argc() == 3)
3539 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
3543 else if (!strcmp(Cmd_Argv(1), "shadows"))
3545 if (Cmd_Argc() != 3)
3547 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3550 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3552 else if (!strcmp(Cmd_Argv(1), "corona"))
3554 if (Cmd_Argc() != 3)
3556 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3559 corona = atof(Cmd_Argv(2));
3561 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3563 if (Cmd_Argc() != 3)
3565 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3568 coronasizescale = atof(Cmd_Argv(2));
3570 else if (!strcmp(Cmd_Argv(1), "ambient"))
3572 if (Cmd_Argc() != 3)
3574 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3577 ambientscale = atof(Cmd_Argv(2));
3579 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3581 if (Cmd_Argc() != 3)
3583 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3586 diffusescale = atof(Cmd_Argv(2));
3588 else if (!strcmp(Cmd_Argv(1), "specular"))
3590 if (Cmd_Argc() != 3)
3592 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3595 specularscale = atof(Cmd_Argv(2));
3597 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3599 if (Cmd_Argc() != 3)
3601 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3604 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3606 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3608 if (Cmd_Argc() != 3)
3610 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3613 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3617 Con_Print("usage: r_editlights_edit [property] [value]\n");
3618 Con_Print("Selected light's properties:\n");
3619 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3620 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3621 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3622 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3623 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3624 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3625 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3626 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3627 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3628 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3629 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3630 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3631 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3632 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3635 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3636 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3639 void R_Shadow_EditLights_EditAll_f(void)
3643 if (!r_editlights.integer)
3645 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3649 for (light = r_shadow_worldlightchain;light;light = light->next)
3651 R_Shadow_SelectLight(light);
3652 R_Shadow_EditLights_Edit_f();
3656 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3658 int lightnumber, lightcount;
3662 if (!r_editlights.integer)
3668 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3669 if (light == r_shadow_selectedlight)
3670 lightnumber = lightcount;
3671 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;
3672 if (r_shadow_selectedlight == NULL)
3674 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3675 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;
3676 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;
3677 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;
3678 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3679 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3680 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3681 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;
3682 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3683 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3684 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3685 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3686 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3687 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;
3688 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;
3691 void R_Shadow_EditLights_ToggleShadow_f(void)
3693 if (!r_editlights.integer)
3695 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3698 if (!r_shadow_selectedlight)
3700 Con_Print("No selected light.\n");
3703 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);
3706 void R_Shadow_EditLights_ToggleCorona_f(void)
3708 if (!r_editlights.integer)
3710 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3713 if (!r_shadow_selectedlight)
3715 Con_Print("No selected light.\n");
3718 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);
3721 void R_Shadow_EditLights_Remove_f(void)
3723 if (!r_editlights.integer)
3725 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3728 if (!r_shadow_selectedlight)
3730 Con_Print("No selected light.\n");
3733 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3734 r_shadow_selectedlight = NULL;
3737 void R_Shadow_EditLights_Help_f(void)
3740 "Documentation on r_editlights system:\n"
3742 "r_editlights : enable/disable editing mode\n"
3743 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3744 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3745 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3746 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3747 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3749 "r_editlights_help : this help\n"
3750 "r_editlights_clear : remove all lights\n"
3751 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3752 "r_editlights_save : save to .rtlights file\n"
3753 "r_editlights_spawn : create a light with default settings\n"
3754 "r_editlights_edit command : edit selected light - more documentation below\n"
3755 "r_editlights_remove : remove selected light\n"
3756 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3757 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3758 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3760 "origin x y z : set light location\n"
3761 "originx x: set x component of light location\n"
3762 "originy y: set y component of light location\n"
3763 "originz z: set z component of light location\n"
3764 "move x y z : adjust light location\n"
3765 "movex x: adjust x component of light location\n"
3766 "movey y: adjust y component of light location\n"
3767 "movez z: adjust z component of light location\n"
3768 "angles x y z : set light angles\n"
3769 "anglesx x: set x component of light angles\n"
3770 "anglesy y: set y component of light angles\n"
3771 "anglesz z: set z component of light angles\n"
3772 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3773 "radius radius : set radius (size) of light\n"
3774 "colorscale grey : multiply color of light (1 does nothing)\n"
3775 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
3776 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
3777 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
3778 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3779 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3780 "shadows 1/0 : turn on/off shadows\n"
3781 "corona n : set corona intensity\n"
3782 "coronasize n : set corona size (0-1)\n"
3783 "ambient n : set ambient intensity (0-1)\n"
3784 "diffuse n : set diffuse intensity (0-1)\n"
3785 "specular n : set specular intensity (0-1)\n"
3786 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
3787 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
3788 "<nothing> : print light properties to console\n"
3792 void R_Shadow_EditLights_CopyInfo_f(void)
3794 if (!r_editlights.integer)
3796 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
3799 if (!r_shadow_selectedlight)
3801 Con_Print("No selected light.\n");
3804 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
3805 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
3806 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
3807 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
3808 if (r_shadow_selectedlight->cubemapname)
3809 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
3811 r_shadow_bufferlight.cubemapname[0] = 0;
3812 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
3813 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
3814 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
3815 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
3816 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
3817 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
3818 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
3821 void R_Shadow_EditLights_PasteInfo_f(void)
3823 if (!r_editlights.integer)
3825 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
3828 if (!r_shadow_selectedlight)
3830 Con_Print("No selected light.\n");
3833 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);
3836 void R_Shadow_EditLights_Init(void)
3838 Cvar_RegisterVariable(&r_editlights);
3839 Cvar_RegisterVariable(&r_editlights_cursordistance);
3840 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3841 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3842 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3843 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3844 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
3845 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
3846 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)");
3847 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
3848 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
3849 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
3850 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)");
3851 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
3852 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
3853 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
3854 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
3855 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
3856 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
3857 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)");