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.125", "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_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
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_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
224 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)"};
225 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
226 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)"};
227 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)"};
228 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatetencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
229 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
230 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
231 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
232 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
233 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
234 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
235 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
237 float r_shadow_attenpower, r_shadow_attenscale;
239 rtlight_t *r_shadow_compilingrtlight;
240 dlight_t *r_shadow_worldlightchain;
241 dlight_t *r_shadow_selectedlight;
242 dlight_t r_shadow_bufferlight;
243 vec3_t r_editlights_cursorlocation;
245 extern int con_vislines;
247 typedef struct cubemapinfo_s
254 #define MAX_CUBEMAPS 256
255 static int numcubemaps;
256 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
258 void R_Shadow_UncompileWorldLights(void);
259 void R_Shadow_ClearWorldLights(void);
260 void R_Shadow_SaveWorldLights(void);
261 void R_Shadow_LoadWorldLights(void);
262 void R_Shadow_LoadLightsFile(void);
263 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
264 void R_Shadow_EditLights_Reload_f(void);
265 void R_Shadow_ValidateCvars(void);
266 static void R_Shadow_MakeTextures(void);
267 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
269 void r_shadow_start(void)
271 // allocate vertex processing arrays
273 r_shadow_attenuation2dtexture = NULL;
274 r_shadow_attenuation3dtexture = NULL;
275 r_shadow_texturepool = NULL;
276 r_shadow_filters_texturepool = NULL;
277 R_Shadow_ValidateCvars();
278 R_Shadow_MakeTextures();
279 maxshadowtriangles = 0;
280 shadowelements = NULL;
281 maxshadowvertices = 0;
282 shadowvertex3f = NULL;
290 shadowmarklist = NULL;
292 r_shadow_buffer_numleafpvsbytes = 0;
293 r_shadow_buffer_leafpvs = NULL;
294 r_shadow_buffer_leaflist = NULL;
295 r_shadow_buffer_numsurfacepvsbytes = 0;
296 r_shadow_buffer_surfacepvs = NULL;
297 r_shadow_buffer_surfacelist = NULL;
300 void r_shadow_shutdown(void)
302 R_Shadow_UncompileWorldLights();
304 r_shadow_attenuation2dtexture = NULL;
305 r_shadow_attenuation3dtexture = NULL;
306 R_FreeTexturePool(&r_shadow_texturepool);
307 R_FreeTexturePool(&r_shadow_filters_texturepool);
308 maxshadowtriangles = 0;
310 Mem_Free(shadowelements);
311 shadowelements = NULL;
313 Mem_Free(shadowvertex3f);
314 shadowvertex3f = NULL;
317 Mem_Free(vertexupdate);
320 Mem_Free(vertexremap);
326 Mem_Free(shadowmark);
329 Mem_Free(shadowmarklist);
330 shadowmarklist = NULL;
332 r_shadow_buffer_numleafpvsbytes = 0;
333 if (r_shadow_buffer_leafpvs)
334 Mem_Free(r_shadow_buffer_leafpvs);
335 r_shadow_buffer_leafpvs = NULL;
336 if (r_shadow_buffer_leaflist)
337 Mem_Free(r_shadow_buffer_leaflist);
338 r_shadow_buffer_leaflist = NULL;
339 r_shadow_buffer_numsurfacepvsbytes = 0;
340 if (r_shadow_buffer_surfacepvs)
341 Mem_Free(r_shadow_buffer_surfacepvs);
342 r_shadow_buffer_surfacepvs = NULL;
343 if (r_shadow_buffer_surfacelist)
344 Mem_Free(r_shadow_buffer_surfacelist);
345 r_shadow_buffer_surfacelist = NULL;
348 void r_shadow_newmap(void)
352 void R_Shadow_Help_f(void)
355 "Documentation on r_shadow system:\n"
357 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
358 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
359 "r_shadow_debuglight : render only this light number (-1 = all)\n"
360 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
361 "r_shadow_gloss2intensity : brightness of forced gloss\n"
362 "r_shadow_glossintensity : brightness of textured gloss\n"
363 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
364 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
365 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
366 "r_shadow_portallight : use portal visibility for static light precomputation\n"
367 "r_shadow_projectdistance : shadow volume projection distance\n"
368 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
369 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\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_svbspculling);
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_realtime_world_compilesvbsp);
411 Cvar_RegisterVariable(&r_shadow_scissor);
412 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
413 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
414 Cvar_RegisterVariable(&r_shadow_texture3d);
415 Cvar_RegisterVariable(&gl_ext_separatestencil);
416 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
417 if (gamemode == GAME_TENEBRAE)
419 Cvar_SetValue("r_shadow_gloss", 2);
420 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
422 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
423 R_Shadow_EditLights_Init();
424 r_shadow_worldlightchain = NULL;
425 maxshadowtriangles = 0;
426 shadowelements = NULL;
427 maxshadowvertices = 0;
428 shadowvertex3f = NULL;
436 shadowmarklist = NULL;
438 r_shadow_buffer_numleafpvsbytes = 0;
439 r_shadow_buffer_leafpvs = NULL;
440 r_shadow_buffer_leaflist = NULL;
441 r_shadow_buffer_numsurfacepvsbytes = 0;
442 r_shadow_buffer_surfacepvs = NULL;
443 r_shadow_buffer_surfacelist = NULL;
444 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
447 matrix4x4_t matrix_attenuationxyz =
450 {0.5, 0.0, 0.0, 0.5},
451 {0.0, 0.5, 0.0, 0.5},
452 {0.0, 0.0, 0.5, 0.5},
457 matrix4x4_t matrix_attenuationz =
460 {0.0, 0.0, 0.5, 0.5},
461 {0.0, 0.0, 0.0, 0.5},
462 {0.0, 0.0, 0.0, 0.5},
467 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
469 // make sure shadowelements is big enough for this volume
470 if (maxshadowtriangles < numtriangles)
472 maxshadowtriangles = numtriangles;
474 Mem_Free(shadowelements);
475 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
477 // make sure shadowvertex3f is big enough for this volume
478 if (maxshadowvertices < numvertices)
480 maxshadowvertices = numvertices;
482 Mem_Free(shadowvertex3f);
483 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
487 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
489 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
490 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
491 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
493 if (r_shadow_buffer_leafpvs)
494 Mem_Free(r_shadow_buffer_leafpvs);
495 if (r_shadow_buffer_leaflist)
496 Mem_Free(r_shadow_buffer_leaflist);
497 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
498 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
499 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
501 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
503 if (r_shadow_buffer_surfacepvs)
504 Mem_Free(r_shadow_buffer_surfacepvs);
505 if (r_shadow_buffer_surfacelist)
506 Mem_Free(r_shadow_buffer_surfacelist);
507 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
508 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
509 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
513 void R_Shadow_PrepareShadowMark(int numtris)
515 // make sure shadowmark is big enough for this volume
516 if (maxshadowmark < numtris)
518 maxshadowmark = numtris;
520 Mem_Free(shadowmark);
522 Mem_Free(shadowmarklist);
523 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
524 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
528 // if shadowmarkcount wrapped we clear the array and adjust accordingly
529 if (shadowmarkcount == 0)
532 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
537 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)
540 int outtriangles = 0, outvertices = 0;
543 float ratio, direction[3], projectvector[3];
545 if (projectdirection)
546 VectorScale(projectdirection, projectdistance, projectvector);
548 VectorClear(projectvector);
550 if (maxvertexupdate < innumvertices)
552 maxvertexupdate = innumvertices;
554 Mem_Free(vertexupdate);
556 Mem_Free(vertexremap);
557 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
558 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
562 if (vertexupdatenum == 0)
565 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
566 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
569 for (i = 0;i < numshadowmarktris;i++)
570 shadowmark[shadowmarktris[i]] = shadowmarkcount;
572 // create the vertices
573 if (projectdirection)
575 for (i = 0;i < numshadowmarktris;i++)
577 element = inelement3i + shadowmarktris[i] * 3;
578 for (j = 0;j < 3;j++)
580 if (vertexupdate[element[j]] != vertexupdatenum)
582 vertexupdate[element[j]] = vertexupdatenum;
583 vertexremap[element[j]] = outvertices;
584 vertex = invertex3f + element[j] * 3;
585 // project one copy of the vertex according to projectvector
586 VectorCopy(vertex, outvertex3f);
587 VectorAdd(vertex, projectvector, (outvertex3f + 3));
596 for (i = 0;i < numshadowmarktris;i++)
598 element = inelement3i + shadowmarktris[i] * 3;
599 for (j = 0;j < 3;j++)
601 if (vertexupdate[element[j]] != vertexupdatenum)
603 vertexupdate[element[j]] = vertexupdatenum;
604 vertexremap[element[j]] = outvertices;
605 vertex = invertex3f + element[j] * 3;
606 // project one copy of the vertex to the sphere radius of the light
607 // (FIXME: would projecting it to the light box be better?)
608 VectorSubtract(vertex, projectorigin, direction);
609 ratio = projectdistance / VectorLength(direction);
610 VectorCopy(vertex, outvertex3f);
611 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
619 for (i = 0;i < numshadowmarktris;i++)
621 int remappedelement[3];
623 const int *neighbortriangle;
625 markindex = shadowmarktris[i] * 3;
626 element = inelement3i + markindex;
627 neighbortriangle = inneighbor3i + markindex;
628 // output the front and back triangles
629 outelement3i[0] = vertexremap[element[0]];
630 outelement3i[1] = vertexremap[element[1]];
631 outelement3i[2] = vertexremap[element[2]];
632 outelement3i[3] = vertexremap[element[2]] + 1;
633 outelement3i[4] = vertexremap[element[1]] + 1;
634 outelement3i[5] = vertexremap[element[0]] + 1;
638 // output the sides (facing outward from this triangle)
639 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
641 remappedelement[0] = vertexremap[element[0]];
642 remappedelement[1] = vertexremap[element[1]];
643 outelement3i[0] = remappedelement[1];
644 outelement3i[1] = remappedelement[0];
645 outelement3i[2] = remappedelement[0] + 1;
646 outelement3i[3] = remappedelement[1];
647 outelement3i[4] = remappedelement[0] + 1;
648 outelement3i[5] = remappedelement[1] + 1;
653 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
655 remappedelement[1] = vertexremap[element[1]];
656 remappedelement[2] = vertexremap[element[2]];
657 outelement3i[0] = remappedelement[2];
658 outelement3i[1] = remappedelement[1];
659 outelement3i[2] = remappedelement[1] + 1;
660 outelement3i[3] = remappedelement[2];
661 outelement3i[4] = remappedelement[1] + 1;
662 outelement3i[5] = remappedelement[2] + 1;
667 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
669 remappedelement[0] = vertexremap[element[0]];
670 remappedelement[2] = vertexremap[element[2]];
671 outelement3i[0] = remappedelement[0];
672 outelement3i[1] = remappedelement[2];
673 outelement3i[2] = remappedelement[2] + 1;
674 outelement3i[3] = remappedelement[0];
675 outelement3i[4] = remappedelement[2] + 1;
676 outelement3i[5] = remappedelement[0] + 1;
683 *outnumvertices = outvertices;
687 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)
690 if (projectdistance < 0.1)
692 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
695 if (!numverts || !nummarktris)
697 // make sure shadowelements is big enough for this volume
698 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
699 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
700 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
701 r_refdef.stats.lights_dynamicshadowtriangles += tris;
702 R_Shadow_RenderVolume(outverts, tris, shadowvertex3f, shadowelements);
705 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)
711 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
713 tend = firsttriangle + numtris;
714 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
715 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
716 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
718 // surface box entirely inside light box, no box cull
719 if (projectdirection)
721 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
723 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
724 if (DotProduct(normal, projectdirection) < 0)
725 shadowmarklist[numshadowmark++] = t;
730 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
731 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
732 shadowmarklist[numshadowmark++] = t;
737 // surface box not entirely inside light box, cull each triangle
738 if (projectdirection)
740 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
742 v[0] = invertex3f + e[0] * 3;
743 v[1] = invertex3f + e[1] * 3;
744 v[2] = invertex3f + e[2] * 3;
745 TriangleNormal(v[0], v[1], v[2], normal);
746 if (DotProduct(normal, projectdirection) < 0
747 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
748 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
749 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
750 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
751 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
752 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
753 shadowmarklist[numshadowmark++] = t;
758 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
760 v[0] = invertex3f + e[0] * 3;
761 v[1] = invertex3f + e[1] * 3;
762 v[2] = invertex3f + e[2] * 3;
763 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
764 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
765 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
766 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
767 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
768 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
769 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
770 shadowmarklist[numshadowmark++] = t;
776 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
778 if (r_shadow_compilingrtlight)
780 // if we're compiling an rtlight, capture the mesh
781 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
784 r_refdef.stats.lights_shadowtriangles += numtriangles;
786 R_Mesh_VertexPointer(vertex3f);
787 GL_LockArrays(0, numvertices);
788 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
790 // decrement stencil if backface is behind depthbuffer
791 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
792 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
793 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
794 // increment stencil if frontface is behind depthbuffer
795 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
796 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
798 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
803 static void R_Shadow_MakeTextures(void)
806 float v[3], intensity;
808 R_FreeTexturePool(&r_shadow_texturepool);
809 r_shadow_texturepool = R_AllocTexturePool();
810 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
811 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
812 #define ATTEN2DSIZE 64
813 #define ATTEN3DSIZE 32
814 data = (unsigned char *)Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
815 for (y = 0;y < ATTEN2DSIZE;y++)
817 for (x = 0;x < ATTEN2DSIZE;x++)
819 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
820 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
822 intensity = 1.0f - sqrt(DotProduct(v, v));
824 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
825 d = (int)bound(0, intensity, 255);
826 data[(y*ATTEN2DSIZE+x)*4+0] = d;
827 data[(y*ATTEN2DSIZE+x)*4+1] = d;
828 data[(y*ATTEN2DSIZE+x)*4+2] = d;
829 data[(y*ATTEN2DSIZE+x)*4+3] = d;
832 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
833 if (r_shadow_texture3d.integer && gl_texture3d)
835 for (z = 0;z < ATTEN3DSIZE;z++)
837 for (y = 0;y < ATTEN3DSIZE;y++)
839 for (x = 0;x < ATTEN3DSIZE;x++)
841 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
842 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
843 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
844 intensity = 1.0f - sqrt(DotProduct(v, v));
846 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
847 d = (int)bound(0, intensity, 255);
848 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
849 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
850 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
851 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
855 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
860 void R_Shadow_ValidateCvars(void)
862 if (r_shadow_texture3d.integer && !gl_texture3d)
863 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
864 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
865 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
866 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
867 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
870 // light currently being rendered
871 rtlight_t *r_shadow_rtlight;
873 // this is the location of the light in entity space
874 vec3_t r_shadow_entitylightorigin;
875 // this transforms entity coordinates to light filter cubemap coordinates
876 // (also often used for other purposes)
877 matrix4x4_t r_shadow_entitytolight;
878 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
879 // of attenuation texturing in full 3D (Z result often ignored)
880 matrix4x4_t r_shadow_entitytoattenuationxyz;
881 // this transforms only the Z to S, and T is always 0.5
882 matrix4x4_t r_shadow_entitytoattenuationz;
884 void R_Shadow_RenderMode_Begin(void)
886 R_Shadow_ValidateCvars();
888 if (!r_shadow_attenuation2dtexture
889 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
890 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
891 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
892 R_Shadow_MakeTextures();
895 R_Mesh_ColorPointer(NULL);
896 R_Mesh_ResetTextureState();
897 GL_BlendFunc(GL_ONE, GL_ZERO);
900 GL_Color(0, 0, 0, 1);
901 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
903 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
905 if (gl_ext_separatestencil.integer)
906 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
907 else if (gl_ext_stenciltwoside.integer)
908 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
910 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
912 if (r_glsl.integer && gl_support_fragment_shader)
913 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
914 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
915 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
917 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
920 void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
922 r_shadow_rtlight = rtlight;
925 void R_Shadow_RenderMode_Reset(void)
928 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
930 qglUseProgramObjectARB(0);CHECKGLERROR
932 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
934 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
936 R_Mesh_ColorPointer(NULL);
937 R_Mesh_ResetTextureState();
940 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
941 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
942 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
943 qglStencilMask(~0);CHECKGLERROR
944 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
945 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
946 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
947 GL_Color(1, 1, 1, 1);
948 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
949 GL_BlendFunc(GL_ONE, GL_ZERO);
952 void R_Shadow_RenderMode_StencilShadowVolumes(void)
955 R_Shadow_RenderMode_Reset();
956 GL_ColorMask(0, 0, 0, 0);
957 qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
958 qglDepthFunc(GL_LESS);CHECKGLERROR
959 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
960 r_shadow_rendermode = r_shadow_shadowingrendermode;
961 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SEPARATESTENCIL)
963 GL_CullFace(GL_NONE);
964 qglStencilOpSeparate(GL_BACK, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR // quake is backwards, this is front faces
965 qglStencilOpSeparate(GL_FRONT, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR // quake is backwards, this is back faces
967 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
969 GL_CullFace(GL_NONE);
970 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
971 qglActiveStencilFaceEXT(GL_BACK);CHECKGLERROR // quake is backwards, this is front faces
972 qglStencilMask(~0);CHECKGLERROR
973 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
974 qglActiveStencilFaceEXT(GL_FRONT);CHECKGLERROR // quake is backwards, this is back faces
975 qglStencilMask(~0);CHECKGLERROR
976 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
978 GL_Clear(GL_STENCIL_BUFFER_BIT);
979 r_refdef.stats.lights_clears++;
982 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
985 R_Shadow_RenderMode_Reset();
986 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
989 qglDepthFunc(GL_EQUAL);CHECKGLERROR
993 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
994 // only draw light where this geometry was already rendered AND the
995 // stencil is 128 (values other than this mean shadow)
996 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
998 r_shadow_rendermode = r_shadow_lightingrendermode;
999 // do global setup needed for the chosen lighting mode
1000 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1002 R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
1003 R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
1004 R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
1005 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_rtlight->currentcubemap)); // light filter
1006 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
1007 R_Mesh_TexBind(5, R_GetTexture(r_texture_white)); // pants
1008 R_Mesh_TexBind(6, R_GetTexture(r_texture_white)); // shirt
1009 R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); // lightmap
1010 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); // deluxemap
1011 R_Mesh_TexBind(9, R_GetTexture(r_texture_black)); // glow
1012 //R_Mesh_TexMatrix(3, r_shadow_entitytolight); // light filter matrix
1013 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1014 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1019 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1022 R_Shadow_RenderMode_Reset();
1023 GL_BlendFunc(GL_ONE, GL_ONE);
1024 GL_DepthTest(r_showshadowvolumes.integer < 2);
1025 GL_Color(0.0, 0.0125 * r_view.colorscale, 0.1 * r_view.colorscale, 1);
1026 qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1027 GL_CullFace(GL_NONE);
1028 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1031 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1034 R_Shadow_RenderMode_Reset();
1035 GL_BlendFunc(GL_ONE, GL_ONE);
1036 GL_DepthTest(r_showlighting.integer < 2);
1037 GL_Color(0.1 * r_view.colorscale, 0.0125 * r_view.colorscale, 0, 1);
1040 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1044 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1045 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1047 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1050 void R_Shadow_RenderMode_End(void)
1053 R_Shadow_RenderMode_Reset();
1054 R_Shadow_RenderMode_ActiveLight(NULL);
1056 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1057 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1060 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1062 int i, ix1, iy1, ix2, iy2;
1063 float x1, y1, x2, y2;
1066 mplane_t planes[11];
1067 float vertex3f[256*3];
1069 // if view is inside the light box, just say yes it's visible
1070 if (BoxesOverlap(r_view.origin, r_view.origin, mins, maxs))
1072 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1076 // create a temporary brush describing the area the light can affect in worldspace
1077 VectorNegate(r_view.frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -r_view.frustum[0].dist;
1078 VectorNegate(r_view.frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -r_view.frustum[1].dist;
1079 VectorNegate(r_view.frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -r_view.frustum[2].dist;
1080 VectorNegate(r_view.frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -r_view.frustum[3].dist;
1081 VectorNegate(r_view.frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -r_view.frustum[4].dist;
1082 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1083 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1084 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1085 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1086 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1087 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1089 // turn the brush into a mesh
1090 memset(&mesh, 0, sizeof(rmesh_t));
1091 mesh.maxvertices = 256;
1092 mesh.vertex3f = vertex3f;
1093 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1094 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1096 // if that mesh is empty, the light is not visible at all
1097 if (!mesh.numvertices)
1100 if (!r_shadow_scissor.integer)
1103 // if that mesh is not empty, check what area of the screen it covers
1104 x1 = y1 = x2 = y2 = 0;
1106 //Con_Printf("%i vertices to transform...\n", mesh.numvertices);
1107 for (i = 0;i < mesh.numvertices;i++)
1109 VectorCopy(mesh.vertex3f + i * 3, v);
1110 GL_TransformToScreen(v, v2);
1111 //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]);
1114 if (x1 > v2[0]) x1 = v2[0];
1115 if (x2 < v2[0]) x2 = v2[0];
1116 if (y1 > v2[1]) y1 = v2[1];
1117 if (y2 < v2[1]) y2 = v2[1];
1126 // now convert the scissor rectangle to integer screen coordinates
1127 ix1 = (int)(x1 - 1.0f);
1128 iy1 = (int)(y1 - 1.0f);
1129 ix2 = (int)(x2 + 1.0f);
1130 iy2 = (int)(y2 + 1.0f);
1131 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1133 // clamp it to the screen
1134 if (ix1 < r_view.x) ix1 = r_view.x;
1135 if (iy1 < r_view.y) iy1 = r_view.y;
1136 if (ix2 > r_view.x + r_view.width) ix2 = r_view.x + r_view.width;
1137 if (iy2 > r_view.y + r_view.height) iy2 = r_view.y + r_view.height;
1139 // if it is inside out, it's not visible
1140 if (ix2 <= ix1 || iy2 <= iy1)
1143 // the light area is visible, set up the scissor rectangle
1144 GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1145 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1146 //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1147 r_refdef.stats.lights_scissored++;
1151 static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor)
1153 int numverts = surface->num_vertices;
1154 float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1155 float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1156 float *color4f = rsurface_array_color4f + 4 * surface->num_firstvertex;
1157 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1158 if (r_textureunits.integer >= 3)
1160 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1162 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1163 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1164 if ((dot = DotProduct(n, v)) < 0)
1166 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1167 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]);
1168 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]);
1169 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]);
1170 if (r_refdef.fogenabled)
1172 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1173 VectorScale(color4f, f, color4f);
1177 VectorClear(color4f);
1181 else if (r_textureunits.integer >= 2)
1183 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1185 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1186 if ((dist = fabs(v[2])) < 1)
1188 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1189 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1190 if ((dot = DotProduct(n, v)) < 0)
1192 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1193 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1194 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1195 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1199 color4f[0] = ambientcolor[0] * distintensity;
1200 color4f[1] = ambientcolor[1] * distintensity;
1201 color4f[2] = ambientcolor[2] * distintensity;
1203 if (r_refdef.fogenabled)
1205 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1206 VectorScale(color4f, f, color4f);
1210 VectorClear(color4f);
1216 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1218 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1219 if ((dist = DotProduct(v, v)) < 1)
1222 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1223 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1224 if ((dot = DotProduct(n, v)) < 0)
1226 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1227 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1228 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1229 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1233 color4f[0] = ambientcolor[0] * distintensity;
1234 color4f[1] = ambientcolor[1] * distintensity;
1235 color4f[2] = ambientcolor[2] * distintensity;
1237 if (r_refdef.fogenabled)
1239 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1240 VectorScale(color4f, f, color4f);
1244 VectorClear(color4f);
1250 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1252 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int numsurfaces, msurface_t **surfacelist)
1254 int surfacelistindex;
1255 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1257 const msurface_t *surface = surfacelist[surfacelistindex];
1259 float *out3f = rsurface_array_texcoord3f + 3 * surface->num_firstvertex;
1260 const float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1261 const float *svector3f = rsurface_svector3f + 3 * surface->num_firstvertex;
1262 const float *tvector3f = rsurface_tvector3f + 3 * surface->num_firstvertex;
1263 const float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1265 for (i = 0;i < surface->num_vertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1267 VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1268 // the cubemap normalizes this for us
1269 out3f[0] = DotProduct(svector3f, lightdir);
1270 out3f[1] = DotProduct(tvector3f, lightdir);
1271 out3f[2] = DotProduct(normal3f, lightdir);
1276 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int numsurfaces, msurface_t **surfacelist)
1278 int surfacelistindex;
1279 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1281 const msurface_t *surface = surfacelist[surfacelistindex];
1283 float *out3f = rsurface_array_texcoord3f + 3 * surface->num_firstvertex;
1284 const float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1285 const float *svector3f = rsurface_svector3f + 3 * surface->num_firstvertex;
1286 const float *tvector3f = rsurface_tvector3f + 3 * surface->num_firstvertex;
1287 const float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1288 float lightdir[3], eyedir[3], halfdir[3];
1289 for (i = 0;i < surface->num_vertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1291 VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1292 VectorNormalize(lightdir);
1293 VectorSubtract(rsurface_modelorg, vertex3f, eyedir);
1294 VectorNormalize(eyedir);
1295 VectorAdd(lightdir, eyedir, halfdir);
1296 // the cubemap normalizes this for us
1297 out3f[0] = DotProduct(svector3f, halfdir);
1298 out3f[1] = DotProduct(tvector3f, halfdir);
1299 out3f[2] = DotProduct(normal3f, halfdir);
1304 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)
1306 // used to display how many times a surface is lit for level design purposes
1307 GL_Color(0.1 * r_view.colorscale, 0.025 * r_view.colorscale, 0, 1);
1308 R_Mesh_ColorPointer(NULL);
1309 R_Mesh_ResetTextureState();
1310 RSurf_PrepareVerticesForBatch(false, false, numsurfaces, surfacelist);
1311 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1312 GL_LockArrays(0, 0);
1315 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)
1317 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1318 RSurf_PrepareVerticesForBatch(true, true, numsurfaces, surfacelist);
1319 R_SetupSurfaceShader(lightcolorbase, false);
1320 R_Mesh_TexCoordPointer(0, 2, rsurface_model->surfmesh.data_texcoordtexture2f);
1321 R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
1322 R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
1323 R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
1324 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1326 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1328 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1329 GL_LockArrays(0, 0);
1330 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1332 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1336 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(int numsurfaces, msurface_t **surfacelist, float r, float g, float b)
1338 // shared final code for all the dot3 layers
1340 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1341 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1343 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1344 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1345 GL_LockArrays(0, 0);
1349 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
1352 // colorscale accounts for how much we multiply the brightness
1355 // mult is how many times the final pass of the lighting will be
1356 // performed to get more brightness than otherwise possible.
1358 // Limit mult to 64 for sanity sake.
1360 if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1362 // 3 3D combine path (Geforce3, Radeon 8500)
1363 memset(&m, 0, sizeof(m));
1364 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1365 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1366 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1367 m.tex[1] = R_GetTexture(basetexture);
1368 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1369 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1370 m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1371 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1372 m.texmatrix[2] = r_shadow_entitytolight;
1373 GL_BlendFunc(GL_ONE, GL_ONE);
1375 else if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1377 // 2 3D combine path (Geforce3, original Radeon)
1378 memset(&m, 0, sizeof(m));
1379 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1380 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1381 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1382 m.tex[1] = R_GetTexture(basetexture);
1383 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1384 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1385 GL_BlendFunc(GL_ONE, GL_ONE);
1387 else if (r_textureunits.integer >= 4 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1389 // 4 2D combine path (Geforce3, Radeon 8500)
1390 memset(&m, 0, sizeof(m));
1391 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1392 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1393 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1394 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1395 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1396 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1397 m.tex[2] = R_GetTexture(basetexture);
1398 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1399 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1400 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1402 m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1403 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1404 m.texmatrix[3] = r_shadow_entitytolight;
1406 GL_BlendFunc(GL_ONE, GL_ONE);
1408 else if (r_textureunits.integer >= 3 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1410 // 3 2D combine path (Geforce3, original Radeon)
1411 memset(&m, 0, sizeof(m));
1412 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1413 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1414 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1415 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1416 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1417 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1418 m.tex[2] = R_GetTexture(basetexture);
1419 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1420 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1421 GL_BlendFunc(GL_ONE, GL_ONE);
1425 // 2/2/2 2D combine path (any dot3 card)
1426 memset(&m, 0, sizeof(m));
1427 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1428 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1429 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1430 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1431 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1432 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1433 R_Mesh_TextureState(&m);
1434 GL_ColorMask(0,0,0,1);
1435 GL_BlendFunc(GL_ONE, GL_ZERO);
1436 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1437 GL_LockArrays(0, 0);
1440 memset(&m, 0, sizeof(m));
1441 m.tex[0] = R_GetTexture(basetexture);
1442 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1443 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1444 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1446 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1447 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1448 m.texmatrix[1] = r_shadow_entitytolight;
1450 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1452 // this final code is shared
1453 R_Mesh_TextureState(&m);
1454 R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1457 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)
1460 // colorscale accounts for how much we multiply the brightness
1463 // mult is how many times the final pass of the lighting will be
1464 // performed to get more brightness than otherwise possible.
1466 // Limit mult to 64 for sanity sake.
1468 // generate normalization cubemap texcoords
1469 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(numsurfaces, surfacelist);
1470 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1472 // 3/2 3D combine path (Geforce3, Radeon 8500)
1473 memset(&m, 0, sizeof(m));
1474 m.tex[0] = R_GetTexture(normalmaptexture);
1475 m.texcombinergb[0] = GL_REPLACE;
1476 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1477 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1478 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1479 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1480 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1481 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1482 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1483 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1484 R_Mesh_TextureState(&m);
1485 GL_ColorMask(0,0,0,1);
1486 GL_BlendFunc(GL_ONE, GL_ZERO);
1487 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1488 GL_LockArrays(0, 0);
1491 memset(&m, 0, sizeof(m));
1492 m.tex[0] = R_GetTexture(basetexture);
1493 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1494 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1495 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1497 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1498 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1499 m.texmatrix[1] = r_shadow_entitytolight;
1501 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1503 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1505 // 1/2/2 3D combine path (original Radeon)
1506 memset(&m, 0, sizeof(m));
1507 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1508 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1509 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1510 R_Mesh_TextureState(&m);
1511 GL_ColorMask(0,0,0,1);
1512 GL_BlendFunc(GL_ONE, GL_ZERO);
1513 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1514 GL_LockArrays(0, 0);
1517 memset(&m, 0, sizeof(m));
1518 m.tex[0] = R_GetTexture(normalmaptexture);
1519 m.texcombinergb[0] = GL_REPLACE;
1520 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1521 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1522 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1523 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1524 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1525 R_Mesh_TextureState(&m);
1526 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1527 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1528 GL_LockArrays(0, 0);
1531 memset(&m, 0, sizeof(m));
1532 m.tex[0] = R_GetTexture(basetexture);
1533 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1534 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1535 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1537 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1538 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1539 m.texmatrix[1] = r_shadow_entitytolight;
1541 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1543 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1545 // 2/2 3D combine path (original Radeon)
1546 memset(&m, 0, sizeof(m));
1547 m.tex[0] = R_GetTexture(normalmaptexture);
1548 m.texcombinergb[0] = GL_REPLACE;
1549 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1550 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1551 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1552 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1553 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1554 R_Mesh_TextureState(&m);
1555 GL_ColorMask(0,0,0,1);
1556 GL_BlendFunc(GL_ONE, GL_ZERO);
1557 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1558 GL_LockArrays(0, 0);
1561 memset(&m, 0, sizeof(m));
1562 m.tex[0] = R_GetTexture(basetexture);
1563 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1564 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1565 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1566 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1567 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1568 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1570 else if (r_textureunits.integer >= 4)
1572 // 4/2 2D combine path (Geforce3, Radeon 8500)
1573 memset(&m, 0, sizeof(m));
1574 m.tex[0] = R_GetTexture(normalmaptexture);
1575 m.texcombinergb[0] = GL_REPLACE;
1576 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1577 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1578 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1579 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1580 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1581 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1582 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1583 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1584 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1585 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1586 m.texmatrix[3] = r_shadow_entitytoattenuationz;
1587 R_Mesh_TextureState(&m);
1588 GL_ColorMask(0,0,0,1);
1589 GL_BlendFunc(GL_ONE, GL_ZERO);
1590 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1591 GL_LockArrays(0, 0);
1594 memset(&m, 0, sizeof(m));
1595 m.tex[0] = R_GetTexture(basetexture);
1596 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1597 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1598 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1600 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1601 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1602 m.texmatrix[1] = r_shadow_entitytolight;
1604 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1608 // 2/2/2 2D combine path (any dot3 card)
1609 memset(&m, 0, sizeof(m));
1610 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1611 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1612 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1613 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1614 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1615 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1616 R_Mesh_TextureState(&m);
1617 GL_ColorMask(0,0,0,1);
1618 GL_BlendFunc(GL_ONE, GL_ZERO);
1619 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1620 GL_LockArrays(0, 0);
1623 memset(&m, 0, sizeof(m));
1624 m.tex[0] = R_GetTexture(normalmaptexture);
1625 m.texcombinergb[0] = GL_REPLACE;
1626 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1627 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1628 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1629 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1630 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1631 R_Mesh_TextureState(&m);
1632 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1633 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1634 GL_LockArrays(0, 0);
1637 memset(&m, 0, sizeof(m));
1638 m.tex[0] = R_GetTexture(basetexture);
1639 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1640 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1641 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1643 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1644 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1645 m.texmatrix[1] = r_shadow_entitytolight;
1647 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1649 // this final code is shared
1650 R_Mesh_TextureState(&m);
1651 R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1654 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)
1656 float glossexponent;
1658 // FIXME: detect blendsquare!
1659 //if (!gl_support_blendsquare)
1662 // generate normalization cubemap texcoords
1663 R_Shadow_GenTexCoords_Specular_NormalCubeMap(numsurfaces, surfacelist);
1664 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1666 // 2/0/0/1/2 3D combine blendsquare path
1667 memset(&m, 0, sizeof(m));
1668 m.tex[0] = R_GetTexture(normalmaptexture);
1669 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1670 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1671 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1672 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1673 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1674 R_Mesh_TextureState(&m);
1675 GL_ColorMask(0,0,0,1);
1676 // this squares the result
1677 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1678 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1679 GL_LockArrays(0, 0);
1681 // second and third pass
1682 R_Mesh_ResetTextureState();
1683 // square alpha in framebuffer a few times to make it shiny
1684 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1685 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1686 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1687 GL_LockArrays(0, 0);
1690 memset(&m, 0, sizeof(m));
1691 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1692 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1693 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1694 R_Mesh_TextureState(&m);
1695 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1696 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1697 GL_LockArrays(0, 0);
1700 memset(&m, 0, sizeof(m));
1701 m.tex[0] = R_GetTexture(glosstexture);
1702 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1703 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1704 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1706 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1707 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1708 m.texmatrix[1] = r_shadow_entitytolight;
1710 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1712 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1714 // 2/0/0/2 3D combine blendsquare path
1715 memset(&m, 0, sizeof(m));
1716 m.tex[0] = R_GetTexture(normalmaptexture);
1717 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1718 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1719 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1720 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1721 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1722 R_Mesh_TextureState(&m);
1723 GL_ColorMask(0,0,0,1);
1724 // this squares the result
1725 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1726 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1727 GL_LockArrays(0, 0);
1729 // second and third pass
1730 R_Mesh_ResetTextureState();
1731 // square alpha in framebuffer a few times to make it shiny
1732 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1733 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1734 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1735 GL_LockArrays(0, 0);
1738 memset(&m, 0, sizeof(m));
1739 m.tex[0] = R_GetTexture(glosstexture);
1740 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1741 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1742 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1743 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1744 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1745 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1749 // 2/0/0/2/2 2D combine blendsquare path
1750 memset(&m, 0, sizeof(m));
1751 m.tex[0] = R_GetTexture(normalmaptexture);
1752 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1753 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1754 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1755 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1756 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1757 R_Mesh_TextureState(&m);
1758 GL_ColorMask(0,0,0,1);
1759 // this squares the result
1760 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1761 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1762 GL_LockArrays(0, 0);
1764 // second and third pass
1765 R_Mesh_ResetTextureState();
1766 // square alpha in framebuffer a few times to make it shiny
1767 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1768 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1769 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1770 GL_LockArrays(0, 0);
1773 memset(&m, 0, sizeof(m));
1774 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1775 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1776 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1777 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1778 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1779 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1780 R_Mesh_TextureState(&m);
1781 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1782 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1783 GL_LockArrays(0, 0);
1786 memset(&m, 0, sizeof(m));
1787 m.tex[0] = R_GetTexture(glosstexture);
1788 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1789 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1790 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1792 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1793 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1794 m.texmatrix[1] = r_shadow_entitytolight;
1796 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1798 // this final code is shared
1799 R_Mesh_TextureState(&m);
1800 R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1803 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)
1805 // ARB path (any Geforce, any Radeon)
1806 qboolean doambient = r_shadow_rtlight->ambientscale > 0;
1807 qboolean dodiffuse = r_shadow_rtlight->diffusescale > 0;
1808 qboolean dospecular = specularscale > 0;
1809 if (!doambient && !dodiffuse && !dospecular)
1811 RSurf_PrepareVerticesForBatch(true, true, numsurfaces, surfacelist);
1812 R_Mesh_ColorPointer(NULL);
1814 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorbase, basetexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1816 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorbase, basetexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1820 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorpants, pantstexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1822 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorpants, pantstexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1827 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1829 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1832 R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(numsurfaces, surfacelist, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale);
1835 void R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(const model_t *model, int numsurfaces, msurface_t **surfacelist, vec3_t diffusecolor2, vec3_t ambientcolor2)
1837 int surfacelistindex;
1839 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1841 const msurface_t *surface = surfacelist[surfacelistindex];
1842 R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(surface, diffusecolor2, ambientcolor2);
1844 for (renders = 0;renders < 64;renders++)
1850 int newnumtriangles;
1852 int newelements[3072];
1856 newnumtriangles = 0;
1858 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1860 const msurface_t *surface = surfacelist[surfacelistindex];
1861 const int *elements = rsurface_model->surfmesh.data_element3i + surface->num_firsttriangle * 3;
1863 // due to low fillrate on the cards this vertex lighting path is
1864 // designed for, we manually cull all triangles that do not
1865 // contain a lit vertex
1866 // this builds batches of triangles from multiple surfaces and
1867 // renders them at once
1868 for (i = 0, e = elements;i < surface->num_triangles;i++, e += 3)
1870 if (VectorLength2(rsurface_array_color4f + e[0] * 4) + VectorLength2(rsurface_array_color4f + e[1] * 4) + VectorLength2(rsurface_array_color4f + e[2] * 4) >= 0.01)
1872 if (newnumtriangles)
1874 firstvertex = min(firstvertex, e[0]);
1875 lastvertex = max(lastvertex, e[0]);
1882 firstvertex = min(firstvertex, e[1]);
1883 lastvertex = max(lastvertex, e[1]);
1884 firstvertex = min(firstvertex, e[2]);
1885 lastvertex = max(lastvertex, e[2]);
1891 if (newnumtriangles >= 1024)
1893 GL_LockArrays(firstvertex, lastvertex - firstvertex + 1);
1894 R_Mesh_Draw(firstvertex, lastvertex - firstvertex + 1, newnumtriangles, newelements);
1895 newnumtriangles = 0;
1902 if (newnumtriangles >= 1)
1904 GL_LockArrays(firstvertex, lastvertex - firstvertex + 1);
1905 R_Mesh_Draw(firstvertex, lastvertex - firstvertex + 1, newnumtriangles, newelements);
1908 GL_LockArrays(0, 0);
1909 // if we couldn't find any lit triangles, exit early
1912 // now reduce the intensity for the next overbright pass
1913 // we have to clamp to 0 here incase the drivers have improper
1914 // handling of negative colors
1915 // (some old drivers even have improper handling of >1 color)
1917 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1921 const msurface_t *surface = surfacelist[surfacelistindex];
1922 for (i = 0, c = rsurface_array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
1924 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
1926 c[0] = max(0, c[0] - 1);
1927 c[1] = max(0, c[1] - 1);
1928 c[2] = max(0, c[2] - 1);
1941 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)
1943 // OpenGL 1.1 path (anything)
1944 model_t *model = rsurface_entity->model;
1945 float ambientcolorbase[3], diffusecolorbase[3];
1946 float ambientcolorpants[3], diffusecolorpants[3];
1947 float ambientcolorshirt[3], diffusecolorshirt[3];
1949 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorbase);
1950 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorbase);
1951 VectorScale(lightcolorpants, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorpants);
1952 VectorScale(lightcolorpants, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorpants);
1953 VectorScale(lightcolorshirt, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorshirt);
1954 VectorScale(lightcolorshirt, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorshirt);
1955 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1956 R_Mesh_ColorPointer(rsurface_array_color4f);
1957 memset(&m, 0, sizeof(m));
1958 m.tex[0] = R_GetTexture(basetexture);
1959 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1960 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1961 if (r_textureunits.integer >= 2)
1964 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1965 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1966 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1967 if (r_textureunits.integer >= 3)
1969 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
1970 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1971 m.texmatrix[2] = r_shadow_entitytoattenuationz;
1972 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1975 R_Mesh_TextureState(&m);
1976 RSurf_PrepareVerticesForBatch(true, false, numsurfaces, surfacelist);
1977 R_Mesh_TexBind(0, R_GetTexture(basetexture));
1978 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorbase, ambientcolorbase);
1981 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
1982 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorpants, ambientcolorpants);
1986 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
1987 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorshirt, ambientcolorshirt);
1991 void R_Shadow_RenderSurfacesLighting(int numsurfaces, msurface_t **surfacelist)
1993 // FIXME: support MATERIALFLAG_NODEPTHTEST
1994 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
1995 // calculate colors to render this texture with
1996 lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * rsurface_entity->colormod[0] * rsurface_texture->currentalpha;
1997 lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * rsurface_entity->colormod[1] * rsurface_texture->currentalpha;
1998 lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * rsurface_entity->colormod[2] * rsurface_texture->currentalpha;
1999 if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) + (r_shadow_rtlight->specularscale * rsurface_texture->specularscale) * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2001 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
2002 GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
2003 if (rsurface_texture->colormapping)
2005 qboolean dopants = rsurface_texture->currentskinframe->pants != NULL && VectorLength2(rsurface_entity->colormap_pantscolor) >= (1.0f / 1048576.0f);
2006 qboolean doshirt = rsurface_texture->currentskinframe->shirt != NULL && VectorLength2(rsurface_entity->colormap_shirtcolor) >= (1.0f / 1048576.0f);
2009 lightcolorpants[0] = lightcolorbase[0] * rsurface_entity->colormap_pantscolor[0];
2010 lightcolorpants[1] = lightcolorbase[1] * rsurface_entity->colormap_pantscolor[1];
2011 lightcolorpants[2] = lightcolorbase[2] * rsurface_entity->colormap_pantscolor[2];
2014 VectorClear(lightcolorpants);
2017 lightcolorshirt[0] = lightcolorbase[0] * rsurface_entity->colormap_shirtcolor[0];
2018 lightcolorshirt[1] = lightcolorbase[1] * rsurface_entity->colormap_shirtcolor[1];
2019 lightcolorshirt[2] = lightcolorbase[2] * rsurface_entity->colormap_shirtcolor[2];
2022 VectorClear(lightcolorshirt);
2023 switch (r_shadow_rendermode)
2025 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2026 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2027 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);
2029 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2030 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);
2032 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2033 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);
2035 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2036 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);
2039 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2045 switch (r_shadow_rendermode)
2047 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2048 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2049 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);
2051 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2052 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);
2054 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2055 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);
2057 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2058 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);
2061 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2067 void R_RTLight_Update(dlight_t *light, int isstatic)
2070 rtlight_t *rtlight = &light->rtlight;
2071 R_RTLight_Uncompile(rtlight);
2072 memset(rtlight, 0, sizeof(*rtlight));
2074 VectorCopy(light->origin, rtlight->shadoworigin);
2075 VectorCopy(light->color, rtlight->color);
2076 rtlight->radius = light->radius;
2077 //rtlight->cullradius = rtlight->radius;
2078 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2079 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2080 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2081 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2082 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2083 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2084 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2085 rtlight->cubemapname[0] = 0;
2086 if (light->cubemapname[0])
2087 strlcpy(rtlight->cubemapname, light->cubemapname, sizeof(rtlight->cubemapname));
2088 else if (light->cubemapnum > 0)
2089 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2090 rtlight->shadow = light->shadow;
2091 rtlight->corona = light->corona;
2092 rtlight->style = light->style;
2093 rtlight->isstatic = isstatic;
2094 rtlight->coronasizescale = light->coronasizescale;
2095 rtlight->ambientscale = light->ambientscale;
2096 rtlight->diffusescale = light->diffusescale;
2097 rtlight->specularscale = light->specularscale;
2098 rtlight->flags = light->flags;
2099 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2100 // this has to scale both rotate and translate because this is an already
2101 // inverted matrix (it transforms from world to light space, not the other
2103 scale = 1.0 / rtlight->radius;
2104 Matrix4x4_Scale(&rtlight->matrix_worldtolight, scale, scale);
2107 // compiles rtlight geometry
2108 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2109 void R_RTLight_Compile(rtlight_t *rtlight)
2111 int shadowmeshes, shadowtris, numleafs, numleafpvsbytes, numsurfaces;
2112 entity_render_t *ent = r_refdef.worldentity;
2113 model_t *model = r_refdef.worldmodel;
2114 unsigned char *data;
2116 // compile the light
2117 rtlight->compiled = true;
2118 rtlight->static_numleafs = 0;
2119 rtlight->static_numleafpvsbytes = 0;
2120 rtlight->static_leaflist = NULL;
2121 rtlight->static_leafpvs = NULL;
2122 rtlight->static_numsurfaces = 0;
2123 rtlight->static_surfacelist = NULL;
2124 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2125 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2126 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2127 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2128 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2129 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2131 if (model && model->GetLightInfo)
2133 // this variable must be set for the CompileShadowVolume code
2134 r_shadow_compilingrtlight = rtlight;
2135 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
2136 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);
2137 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2138 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2139 rtlight->static_numleafs = numleafs;
2140 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2141 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2142 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2143 rtlight->static_numsurfaces = numsurfaces;
2144 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2146 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2147 if (numleafpvsbytes)
2148 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2150 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2151 if (model->CompileShadowVolume && rtlight->shadow)
2152 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2153 // now we're done compiling the rtlight
2154 r_shadow_compilingrtlight = NULL;
2158 // use smallest available cullradius - box radius or light radius
2159 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2160 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2164 if (rtlight->static_meshchain_shadow)
2167 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2170 shadowtris += mesh->numtriangles;
2174 if (developer.integer >= 10)
2175 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);
2178 void R_RTLight_Uncompile(rtlight_t *rtlight)
2180 if (rtlight->compiled)
2182 if (rtlight->static_meshchain_shadow)
2183 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2184 rtlight->static_meshchain_shadow = NULL;
2185 // these allocations are grouped
2186 if (rtlight->static_leaflist)
2187 Mem_Free(rtlight->static_leaflist);
2188 rtlight->static_numleafs = 0;
2189 rtlight->static_numleafpvsbytes = 0;
2190 rtlight->static_leaflist = NULL;
2191 rtlight->static_leafpvs = NULL;
2192 rtlight->static_numsurfaces = 0;
2193 rtlight->static_surfacelist = NULL;
2194 rtlight->compiled = false;
2198 void R_Shadow_UncompileWorldLights(void)
2201 for (light = r_shadow_worldlightchain;light;light = light->next)
2202 R_RTLight_Uncompile(&light->rtlight);
2205 void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfacelist)
2207 model_t *model = ent->model;
2208 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2209 vec_t relativeshadowradius;
2210 if (ent == r_refdef.worldentity)
2212 if (r_shadow_rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2215 R_Mesh_Matrix(&ent->matrix);
2217 for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2219 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2220 R_Mesh_VertexPointer(mesh->vertex3f);
2221 GL_LockArrays(0, mesh->numverts);
2222 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2224 // decrement stencil if backface is behind depthbuffer
2225 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
2226 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2227 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2228 // increment stencil if frontface is behind depthbuffer
2229 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2230 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2232 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2233 GL_LockArrays(0, 0);
2237 else if (numsurfaces)
2239 R_Mesh_Matrix(&ent->matrix);
2240 model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, NULL, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs);
2245 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, relativeshadoworigin);
2246 relativeshadowradius = r_shadow_rtlight->radius / ent->scale;
2247 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2248 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2249 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2250 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2251 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2252 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2253 R_Mesh_Matrix(&ent->matrix);
2254 model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, model->nummodelsurfaces, model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2258 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2260 // set up properties for rendering light onto this entity
2261 RSurf_ActiveEntity(ent, true, true);
2262 Matrix4x4_Concat(&r_shadow_entitytolight, &r_shadow_rtlight->matrix_worldtolight, &ent->matrix);
2263 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2264 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2265 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2266 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2267 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2270 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2272 model_t *model = ent->model;
2273 if (!model->DrawLight)
2275 R_Shadow_SetupEntityLight(ent);
2276 if (ent == r_refdef.worldentity)
2277 model->DrawLight(ent, numsurfaces, surfacelist);
2279 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist);
2282 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2286 int numleafs, numsurfaces;
2287 int *leaflist, *surfacelist;
2288 unsigned char *leafpvs;
2289 int numlightentities;
2290 int numshadowentities;
2291 entity_render_t *lightentities[MAX_EDICTS];
2292 entity_render_t *shadowentities[MAX_EDICTS];
2294 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2295 // skip lights that are basically invisible (color 0 0 0)
2296 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2299 // loading is done before visibility checks because loading should happen
2300 // all at once at the start of a level, not when it stalls gameplay.
2301 // (especially important to benchmarks)
2303 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2304 R_RTLight_Compile(rtlight);
2306 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2308 // look up the light style value at this time
2309 f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2310 VectorScale(rtlight->color, f, rtlight->currentcolor);
2312 if (rtlight->selected)
2314 f = 2 + sin(realtime * M_PI * 4.0);
2315 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2319 // if lightstyle is currently off, don't draw the light
2320 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2323 // if the light box is offscreen, skip it
2324 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2327 VectorCopy(rtlight->cullmins, r_shadow_rtlight_cullmins);
2328 VectorCopy(rtlight->cullmaxs, r_shadow_rtlight_cullmaxs);
2330 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2332 // compiled light, world available and can receive realtime lighting
2333 // retrieve leaf information
2334 numleafs = rtlight->static_numleafs;
2335 leaflist = rtlight->static_leaflist;
2336 leafpvs = rtlight->static_leafpvs;
2337 numsurfaces = rtlight->static_numsurfaces;
2338 surfacelist = rtlight->static_surfacelist;
2340 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2342 // dynamic light, world available and can receive realtime lighting
2343 // calculate lit surfaces and leafs
2344 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces);
2345 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);
2346 leaflist = r_shadow_buffer_leaflist;
2347 leafpvs = r_shadow_buffer_leafpvs;
2348 surfacelist = r_shadow_buffer_surfacelist;
2349 // if the reduced leaf bounds are offscreen, skip it
2350 if (R_CullBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2362 // check if light is illuminating any visible leafs
2365 for (i = 0;i < numleafs;i++)
2366 if (r_viewcache.world_leafvisible[leaflist[i]])
2371 // set up a scissor rectangle for this light
2372 if (R_Shadow_ScissorForBBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2375 // make a list of lit entities and shadow casting entities
2376 numlightentities = 0;
2377 numshadowentities = 0;
2378 // don't count the world unless some surfaces are actually lit
2381 lightentities[numlightentities++] = r_refdef.worldentity;
2382 shadowentities[numshadowentities++] = r_refdef.worldentity;
2384 // add dynamic entities that are lit by the light
2385 if (r_drawentities.integer)
2387 for (i = 0;i < r_refdef.numentities;i++)
2390 entity_render_t *ent = r_refdef.entities[i];
2391 if (BoxesOverlap(ent->mins, ent->maxs, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs)
2392 && (model = ent->model)
2393 && !(ent->flags & RENDER_TRANSPARENT)
2394 && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2396 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2398 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2399 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2400 shadowentities[numshadowentities++] = ent;
2401 if (r_viewcache.entityvisible[i] && (ent->flags & RENDER_LIGHT) && model->DrawLight)
2402 lightentities[numlightentities++] = ent;
2407 // return if there's nothing at all to light
2408 if (!numlightentities)
2411 // don't let sound skip if going slow
2412 if (r_refdef.extraupdate)
2415 // make this the active rtlight for rendering purposes
2416 R_Shadow_RenderMode_ActiveLight(rtlight);
2417 // count this light in the r_speeds
2418 r_refdef.stats.lights++;
2421 if (numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2423 // draw stencil shadow volumes to mask off pixels that are in shadow
2424 // so that they won't receive lighting
2428 R_Shadow_RenderMode_StencilShadowVolumes();
2429 for (i = 0;i < numshadowentities;i++)
2430 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2433 // optionally draw visible shape of the shadow volumes
2434 // for performance analysis by level designers
2435 if (r_showshadowvolumes.integer)
2437 R_Shadow_RenderMode_VisibleShadowVolumes();
2438 for (i = 0;i < numshadowentities;i++)
2439 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2443 if (numlightentities)
2445 // draw lighting in the unmasked areas
2446 R_Shadow_RenderMode_Lighting(usestencil, false);
2447 for (i = 0;i < numlightentities;i++)
2448 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2450 // optionally draw the illuminated areas
2451 // for performance analysis by level designers
2452 if (r_showlighting.integer)
2454 R_Shadow_RenderMode_VisibleLighting(usestencil && !r_showdisabledepthtest.integer, false);
2455 for (i = 0;i < numlightentities;i++)
2456 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2461 void R_ShadowVolumeLighting(qboolean visible)
2466 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2467 R_Shadow_EditLights_Reload_f();
2469 R_Shadow_RenderMode_Begin();
2471 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2472 if (r_shadow_debuglight.integer >= 0)
2474 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2475 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2476 R_DrawRTLight(&light->rtlight, visible);
2479 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2480 if (light->flags & flag)
2481 R_DrawRTLight(&light->rtlight, visible);
2482 if (r_refdef.rtdlight)
2483 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
2484 R_DrawRTLight(&r_refdef.lights[lnum]->rtlight, visible);
2486 R_Shadow_RenderMode_End();
2489 extern void R_SetupView(const matrix4x4_t *matrix);
2490 extern cvar_t r_shadows_throwdistance;
2491 void R_DrawModelShadows(void)
2494 float relativethrowdistance;
2495 entity_render_t *ent;
2496 vec3_t relativelightorigin;
2497 vec3_t relativelightdirection;
2498 vec3_t relativeshadowmins, relativeshadowmaxs;
2501 if (!r_drawentities.integer || !gl_stencil)
2505 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2507 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2509 if (gl_ext_separatestencil.integer)
2510 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
2511 else if (gl_ext_stenciltwoside.integer)
2512 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
2514 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
2516 R_Shadow_RenderMode_StencilShadowVolumes();
2518 for (i = 0;i < r_refdef.numentities;i++)
2520 ent = r_refdef.entities[i];
2521 // cast shadows from anything that is not a submodel of the map
2522 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
2524 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
2525 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
2526 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
2527 VectorNegate(ent->modellight_lightdir, relativelightdirection);
2528 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
2529 R_Mesh_Matrix(&ent->matrix);
2530 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2534 // not really the right mode, but this will disable any silly stencil features
2535 R_Shadow_RenderMode_VisibleLighting(true, true);
2537 // vertex coordinates for a quad that covers the screen exactly
2538 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
2539 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
2540 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
2541 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
2543 // set up ortho view for rendering this pass
2544 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
2545 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2546 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2547 GL_ScissorTest(true);
2548 R_Mesh_Matrix(&identitymatrix);
2549 R_Mesh_ResetTextureState();
2550 R_Mesh_VertexPointer(vertex3f);
2551 R_Mesh_ColorPointer(NULL);
2553 // set up a 50% darkening blend on shadowed areas
2554 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2555 GL_DepthTest(false);
2556 GL_DepthMask(false);
2557 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2558 GL_Color(0, 0, 0, 0.5);
2559 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2560 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
2561 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2562 qglStencilMask(~0);CHECKGLERROR
2563 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
2564 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
2566 // apply the blend to the shadowed areas
2567 R_Mesh_Draw(0, 4, 2, polygonelements);
2569 // restoring the perspective view is done by R_RenderScene
2570 //R_SetupView(&r_view.matrix);
2572 // restore other state to normal
2573 R_Shadow_RenderMode_End();
2577 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2578 typedef struct suffixinfo_s
2581 qboolean flipx, flipy, flipdiagonal;
2584 static suffixinfo_t suffix[3][6] =
2587 {"px", false, false, false},
2588 {"nx", false, false, false},
2589 {"py", false, false, false},
2590 {"ny", false, false, false},
2591 {"pz", false, false, false},
2592 {"nz", false, false, false}
2595 {"posx", false, false, false},
2596 {"negx", false, false, false},
2597 {"posy", false, false, false},
2598 {"negy", false, false, false},
2599 {"posz", false, false, false},
2600 {"negz", false, false, false}
2603 {"rt", true, false, true},
2604 {"lf", false, true, true},
2605 {"ft", true, true, false},
2606 {"bk", false, false, false},
2607 {"up", true, false, true},
2608 {"dn", true, false, true}
2612 static int componentorder[4] = {0, 1, 2, 3};
2614 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2616 int i, j, cubemapsize;
2617 unsigned char *cubemappixels, *image_rgba;
2618 rtexture_t *cubemaptexture;
2620 // must start 0 so the first loadimagepixels has no requested width/height
2622 cubemappixels = NULL;
2623 cubemaptexture = NULL;
2624 // keep trying different suffix groups (posx, px, rt) until one loads
2625 for (j = 0;j < 3 && !cubemappixels;j++)
2627 // load the 6 images in the suffix group
2628 for (i = 0;i < 6;i++)
2630 // generate an image name based on the base and and suffix
2631 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2633 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2635 // an image loaded, make sure width and height are equal
2636 if (image_width == image_height)
2638 // if this is the first image to load successfully, allocate the cubemap memory
2639 if (!cubemappixels && image_width >= 1)
2641 cubemapsize = image_width;
2642 // note this clears to black, so unavailable sides are black
2643 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2645 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2647 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);
2650 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2652 Mem_Free(image_rgba);
2656 // if a cubemap loaded, upload it
2659 if (!r_shadow_filters_texturepool)
2660 r_shadow_filters_texturepool = R_AllocTexturePool();
2661 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2662 Mem_Free(cubemappixels);
2666 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2667 for (j = 0;j < 3;j++)
2668 for (i = 0;i < 6;i++)
2669 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2670 Con_Print(" and was unable to find any of them.\n");
2672 return cubemaptexture;
2675 rtexture_t *R_Shadow_Cubemap(const char *basename)
2678 for (i = 0;i < numcubemaps;i++)
2679 if (!strcasecmp(cubemaps[i].basename, basename))
2680 return cubemaps[i].texture;
2681 if (i >= MAX_CUBEMAPS)
2682 return r_texture_whitecube;
2684 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
2685 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2686 if (!cubemaps[i].texture)
2687 cubemaps[i].texture = r_texture_whitecube;
2688 return cubemaps[i].texture;
2691 void R_Shadow_FreeCubemaps(void)
2694 R_FreeTexturePool(&r_shadow_filters_texturepool);
2697 dlight_t *R_Shadow_NewWorldLight(void)
2700 light = (dlight_t *)Mem_Alloc(r_main_mempool, sizeof(dlight_t));
2701 light->next = r_shadow_worldlightchain;
2702 r_shadow_worldlightchain = light;
2706 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)
2708 VectorCopy(origin, light->origin);
2709 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
2710 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
2711 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
2712 light->color[0] = max(color[0], 0);
2713 light->color[1] = max(color[1], 0);
2714 light->color[2] = max(color[2], 0);
2715 light->radius = max(radius, 0);
2716 light->style = style;
2717 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2719 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2722 light->shadow = shadowenable;
2723 light->corona = corona;
2726 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
2727 light->coronasizescale = coronasizescale;
2728 light->ambientscale = ambientscale;
2729 light->diffusescale = diffusescale;
2730 light->specularscale = specularscale;
2731 light->flags = flags;
2732 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2734 R_RTLight_Update(light, true);
2737 void R_Shadow_FreeWorldLight(dlight_t *light)
2739 dlight_t **lightpointer;
2740 R_RTLight_Uncompile(&light->rtlight);
2741 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2742 if (*lightpointer != light)
2743 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
2744 *lightpointer = light->next;
2748 void R_Shadow_ClearWorldLights(void)
2750 while (r_shadow_worldlightchain)
2751 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2752 r_shadow_selectedlight = NULL;
2753 R_Shadow_FreeCubemaps();
2756 void R_Shadow_SelectLight(dlight_t *light)
2758 if (r_shadow_selectedlight)
2759 r_shadow_selectedlight->selected = false;
2760 r_shadow_selectedlight = light;
2761 if (r_shadow_selectedlight)
2762 r_shadow_selectedlight->selected = true;
2765 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2767 // this is never batched (there can be only one)
2768 float scale = r_editlights_cursorgrid.value * 0.5f;
2769 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);
2772 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2774 // this is never batched (due to the ent parameter changing every time)
2775 // so numsurfaces == 1 and surfacelist[0] == lightnumber
2777 const dlight_t *light = (dlight_t *)ent;
2779 if (light->selected)
2780 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2783 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);
2786 void R_Shadow_DrawLightSprites(void)
2791 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
2792 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 1+(i % 5), &light->rtlight);
2793 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
2796 void R_Shadow_SelectLightInView(void)
2798 float bestrating, rating, temp[3];
2799 dlight_t *best, *light;
2802 for (light = r_shadow_worldlightchain;light;light = light->next)
2804 VectorSubtract(light->origin, r_view.origin, temp);
2805 rating = (DotProduct(temp, r_view.forward) / sqrt(DotProduct(temp, temp)));
2808 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2809 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_view.origin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
2811 bestrating = rating;
2816 R_Shadow_SelectLight(best);
2819 void R_Shadow_LoadWorldLights(void)
2821 int n, a, style, shadow, flags;
2822 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
2823 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
2824 if (r_refdef.worldmodel == NULL)
2826 Con_Print("No map loaded.\n");
2829 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2830 strlcat (name, ".rtlights", sizeof (name));
2831 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
2841 for (;COM_Parse(t, true) && strcmp(
2842 if (COM_Parse(t, true))
2844 if (com_token[0] == '!')
2847 origin[0] = atof(com_token+1);
2850 origin[0] = atof(com_token);
2855 while (*s && *s != '\n' && *s != '\r')
2861 // check for modifier flags
2868 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);
2871 flags = LIGHTFLAG_REALTIMEMODE;
2879 coronasizescale = 0.25f;
2881 VectorClear(angles);
2884 if (a < 9 || !strcmp(cubemapname, "\"\""))
2886 // remove quotes on cubemapname
2887 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
2890 namelen = strlen(cubemapname) - 2;
2891 memmove(cubemapname, cubemapname + 1, namelen);
2892 cubemapname[namelen] = '\0';
2896 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);
2899 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
2907 Con_Printf("invalid rtlights file \"%s\"\n", name);
2908 Mem_Free(lightsstring);
2912 void R_Shadow_SaveWorldLights(void)
2915 size_t bufchars, bufmaxchars;
2917 char name[MAX_QPATH];
2918 char line[MAX_INPUTLINE];
2919 if (!r_shadow_worldlightchain)
2921 if (r_refdef.worldmodel == NULL)
2923 Con_Print("No map loaded.\n");
2926 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2927 strlcat (name, ".rtlights", sizeof (name));
2928 bufchars = bufmaxchars = 0;
2930 for (light = r_shadow_worldlightchain;light;light = light->next)
2932 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
2933 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);
2934 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
2935 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]);
2937 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);
2938 if (bufchars + strlen(line) > bufmaxchars)
2940 bufmaxchars = bufchars + strlen(line) + 2048;
2942 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
2946 memcpy(buf, oldbuf, bufchars);
2952 memcpy(buf + bufchars, line, strlen(line));
2953 bufchars += strlen(line);
2957 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
2962 void R_Shadow_LoadLightsFile(void)
2965 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
2966 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2967 if (r_refdef.worldmodel == NULL)
2969 Con_Print("No map loaded.\n");
2972 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2973 strlcat (name, ".lights", sizeof (name));
2974 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
2982 while (*s && *s != '\n' && *s != '\r')
2988 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);
2992 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);
2995 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2996 radius = bound(15, radius, 4096);
2997 VectorScale(color, (2.0f / (8388608.0f)), color);
2998 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3006 Con_Printf("invalid lights file \"%s\"\n", name);
3007 Mem_Free(lightsstring);
3011 // tyrlite/hmap2 light types in the delay field
3012 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3014 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3016 int entnum, style, islight, skin, pflags, effects, type, n;
3019 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3020 char key[256], value[MAX_INPUTLINE];
3022 if (r_refdef.worldmodel == NULL)
3024 Con_Print("No map loaded.\n");
3027 // try to load a .ent file first
3028 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3029 strlcat (key, ".ent", sizeof (key));
3030 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3031 // and if that is not found, fall back to the bsp file entity string
3033 data = r_refdef.worldmodel->brush.entities;
3036 for (entnum = 0;COM_ParseTokenConsole(&data) && com_token[0] == '{';entnum++)
3038 type = LIGHTTYPE_MINUSX;
3039 origin[0] = origin[1] = origin[2] = 0;
3040 originhack[0] = originhack[1] = originhack[2] = 0;
3041 angles[0] = angles[1] = angles[2] = 0;
3042 color[0] = color[1] = color[2] = 1;
3043 light[0] = light[1] = light[2] = 1;light[3] = 300;
3044 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3054 if (!COM_ParseTokenConsole(&data))
3056 if (com_token[0] == '}')
3057 break; // end of entity
3058 if (com_token[0] == '_')
3059 strlcpy(key, com_token + 1, sizeof(key));
3061 strlcpy(key, com_token, sizeof(key));
3062 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3063 key[strlen(key)-1] = 0;
3064 if (!COM_ParseTokenConsole(&data))
3066 strlcpy(value, com_token, sizeof(value));
3068 // now that we have the key pair worked out...
3069 if (!strcmp("light", key))
3071 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3075 light[0] = vec[0] * (1.0f / 256.0f);
3076 light[1] = vec[0] * (1.0f / 256.0f);
3077 light[2] = vec[0] * (1.0f / 256.0f);
3083 light[0] = vec[0] * (1.0f / 255.0f);
3084 light[1] = vec[1] * (1.0f / 255.0f);
3085 light[2] = vec[2] * (1.0f / 255.0f);
3089 else if (!strcmp("delay", key))
3091 else if (!strcmp("origin", key))
3092 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3093 else if (!strcmp("angle", key))
3094 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3095 else if (!strcmp("angles", key))
3096 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3097 else if (!strcmp("color", key))
3098 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3099 else if (!strcmp("wait", key))
3100 fadescale = atof(value);
3101 else if (!strcmp("classname", key))
3103 if (!strncmp(value, "light", 5))
3106 if (!strcmp(value, "light_fluoro"))
3111 overridecolor[0] = 1;
3112 overridecolor[1] = 1;
3113 overridecolor[2] = 1;
3115 if (!strcmp(value, "light_fluorospark"))
3120 overridecolor[0] = 1;
3121 overridecolor[1] = 1;
3122 overridecolor[2] = 1;
3124 if (!strcmp(value, "light_globe"))
3129 overridecolor[0] = 1;
3130 overridecolor[1] = 0.8;
3131 overridecolor[2] = 0.4;
3133 if (!strcmp(value, "light_flame_large_yellow"))
3138 overridecolor[0] = 1;
3139 overridecolor[1] = 0.5;
3140 overridecolor[2] = 0.1;
3142 if (!strcmp(value, "light_flame_small_yellow"))
3147 overridecolor[0] = 1;
3148 overridecolor[1] = 0.5;
3149 overridecolor[2] = 0.1;
3151 if (!strcmp(value, "light_torch_small_white"))
3156 overridecolor[0] = 1;
3157 overridecolor[1] = 0.5;
3158 overridecolor[2] = 0.1;
3160 if (!strcmp(value, "light_torch_small_walltorch"))
3165 overridecolor[0] = 1;
3166 overridecolor[1] = 0.5;
3167 overridecolor[2] = 0.1;
3171 else if (!strcmp("style", key))
3172 style = atoi(value);
3173 else if (!strcmp("skin", key))
3174 skin = (int)atof(value);
3175 else if (!strcmp("pflags", key))
3176 pflags = (int)atof(value);
3177 else if (!strcmp("effects", key))
3178 effects = (int)atof(value);
3179 else if (r_refdef.worldmodel->type == mod_brushq3)
3181 if (!strcmp("scale", key))
3182 lightscale = atof(value);
3183 if (!strcmp("fade", key))
3184 fadescale = atof(value);
3189 if (lightscale <= 0)
3193 if (color[0] == color[1] && color[0] == color[2])
3195 color[0] *= overridecolor[0];
3196 color[1] *= overridecolor[1];
3197 color[2] *= overridecolor[2];
3199 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3200 color[0] = color[0] * light[0];
3201 color[1] = color[1] * light[1];
3202 color[2] = color[2] * light[2];
3205 case LIGHTTYPE_MINUSX:
3207 case LIGHTTYPE_RECIPX:
3209 VectorScale(color, (1.0f / 16.0f), color);
3211 case LIGHTTYPE_RECIPXX:
3213 VectorScale(color, (1.0f / 16.0f), color);
3216 case LIGHTTYPE_NONE:
3220 case LIGHTTYPE_MINUSXX:
3223 VectorAdd(origin, originhack, origin);
3225 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);
3228 Mem_Free(entfiledata);
3232 void R_Shadow_SetCursorLocationForView(void)
3235 vec3_t dest, endpos;
3237 VectorMA(r_view.origin, r_editlights_cursordistance.value, r_view.forward, dest);
3238 trace = CL_TraceBox(r_view.origin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3239 if (trace.fraction < 1)
3241 dist = trace.fraction * r_editlights_cursordistance.value;
3242 push = r_editlights_cursorpushback.value;
3246 VectorMA(trace.endpos, push, r_view.forward, endpos);
3247 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3251 VectorClear( endpos );
3253 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3254 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3255 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3258 void R_Shadow_UpdateWorldLightSelection(void)
3260 if (r_editlights.integer)
3262 R_Shadow_SetCursorLocationForView();
3263 R_Shadow_SelectLightInView();
3264 R_Shadow_DrawLightSprites();
3267 R_Shadow_SelectLight(NULL);
3270 void R_Shadow_EditLights_Clear_f(void)
3272 R_Shadow_ClearWorldLights();
3275 void R_Shadow_EditLights_Reload_f(void)
3277 if (!r_refdef.worldmodel)
3279 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3280 R_Shadow_ClearWorldLights();
3281 R_Shadow_LoadWorldLights();
3282 if (r_shadow_worldlightchain == NULL)
3284 R_Shadow_LoadLightsFile();
3285 if (r_shadow_worldlightchain == NULL)
3286 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3290 void R_Shadow_EditLights_Save_f(void)
3292 if (!r_refdef.worldmodel)
3294 R_Shadow_SaveWorldLights();
3297 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3299 R_Shadow_ClearWorldLights();
3300 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3303 void R_Shadow_EditLights_ImportLightsFile_f(void)
3305 R_Shadow_ClearWorldLights();
3306 R_Shadow_LoadLightsFile();
3309 void R_Shadow_EditLights_Spawn_f(void)
3312 if (!r_editlights.integer)
3314 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3317 if (Cmd_Argc() != 1)
3319 Con_Print("r_editlights_spawn does not take parameters\n");
3322 color[0] = color[1] = color[2] = 1;
3323 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3326 void R_Shadow_EditLights_Edit_f(void)
3328 vec3_t origin, angles, color;
3329 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3330 int style, shadows, flags, normalmode, realtimemode;
3331 char cubemapname[MAX_INPUTLINE];
3332 if (!r_editlights.integer)
3334 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3337 if (!r_shadow_selectedlight)
3339 Con_Print("No selected light.\n");
3342 VectorCopy(r_shadow_selectedlight->origin, origin);
3343 VectorCopy(r_shadow_selectedlight->angles, angles);
3344 VectorCopy(r_shadow_selectedlight->color, color);
3345 radius = r_shadow_selectedlight->radius;
3346 style = r_shadow_selectedlight->style;
3347 if (r_shadow_selectedlight->cubemapname)
3348 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3351 shadows = r_shadow_selectedlight->shadow;
3352 corona = r_shadow_selectedlight->corona;
3353 coronasizescale = r_shadow_selectedlight->coronasizescale;
3354 ambientscale = r_shadow_selectedlight->ambientscale;
3355 diffusescale = r_shadow_selectedlight->diffusescale;
3356 specularscale = r_shadow_selectedlight->specularscale;
3357 flags = r_shadow_selectedlight->flags;
3358 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3359 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3360 if (!strcmp(Cmd_Argv(1), "origin"))
3362 if (Cmd_Argc() != 5)
3364 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3367 origin[0] = atof(Cmd_Argv(2));
3368 origin[1] = atof(Cmd_Argv(3));
3369 origin[2] = atof(Cmd_Argv(4));
3371 else if (!strcmp(Cmd_Argv(1), "originx"))
3373 if (Cmd_Argc() != 3)
3375 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3378 origin[0] = atof(Cmd_Argv(2));
3380 else if (!strcmp(Cmd_Argv(1), "originy"))
3382 if (Cmd_Argc() != 3)
3384 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3387 origin[1] = atof(Cmd_Argv(2));
3389 else if (!strcmp(Cmd_Argv(1), "originz"))
3391 if (Cmd_Argc() != 3)
3393 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3396 origin[2] = atof(Cmd_Argv(2));
3398 else if (!strcmp(Cmd_Argv(1), "move"))
3400 if (Cmd_Argc() != 5)
3402 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3405 origin[0] += atof(Cmd_Argv(2));
3406 origin[1] += atof(Cmd_Argv(3));
3407 origin[2] += atof(Cmd_Argv(4));
3409 else if (!strcmp(Cmd_Argv(1), "movex"))
3411 if (Cmd_Argc() != 3)
3413 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3416 origin[0] += atof(Cmd_Argv(2));
3418 else if (!strcmp(Cmd_Argv(1), "movey"))
3420 if (Cmd_Argc() != 3)
3422 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3425 origin[1] += atof(Cmd_Argv(2));
3427 else if (!strcmp(Cmd_Argv(1), "movez"))
3429 if (Cmd_Argc() != 3)
3431 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3434 origin[2] += atof(Cmd_Argv(2));
3436 else if (!strcmp(Cmd_Argv(1), "angles"))
3438 if (Cmd_Argc() != 5)
3440 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3443 angles[0] = atof(Cmd_Argv(2));
3444 angles[1] = atof(Cmd_Argv(3));
3445 angles[2] = atof(Cmd_Argv(4));
3447 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3449 if (Cmd_Argc() != 3)
3451 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3454 angles[0] = atof(Cmd_Argv(2));
3456 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3458 if (Cmd_Argc() != 3)
3460 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3463 angles[1] = atof(Cmd_Argv(2));
3465 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3467 if (Cmd_Argc() != 3)
3469 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3472 angles[2] = atof(Cmd_Argv(2));
3474 else if (!strcmp(Cmd_Argv(1), "color"))
3476 if (Cmd_Argc() != 5)
3478 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3481 color[0] = atof(Cmd_Argv(2));
3482 color[1] = atof(Cmd_Argv(3));
3483 color[2] = atof(Cmd_Argv(4));
3485 else if (!strcmp(Cmd_Argv(1), "radius"))
3487 if (Cmd_Argc() != 3)
3489 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3492 radius = atof(Cmd_Argv(2));
3494 else if (!strcmp(Cmd_Argv(1), "colorscale"))
3496 if (Cmd_Argc() == 3)
3498 double scale = atof(Cmd_Argv(2));
3505 if (Cmd_Argc() != 5)
3507 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
3510 color[0] *= atof(Cmd_Argv(2));
3511 color[1] *= atof(Cmd_Argv(3));
3512 color[2] *= atof(Cmd_Argv(4));
3515 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
3517 if (Cmd_Argc() != 3)
3519 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3522 radius *= atof(Cmd_Argv(2));
3524 else if (!strcmp(Cmd_Argv(1), "style"))
3526 if (Cmd_Argc() != 3)
3528 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3531 style = atoi(Cmd_Argv(2));
3533 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3537 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3540 if (Cmd_Argc() == 3)
3541 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
3545 else if (!strcmp(Cmd_Argv(1), "shadows"))
3547 if (Cmd_Argc() != 3)
3549 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3552 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3554 else if (!strcmp(Cmd_Argv(1), "corona"))
3556 if (Cmd_Argc() != 3)
3558 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3561 corona = atof(Cmd_Argv(2));
3563 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3565 if (Cmd_Argc() != 3)
3567 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3570 coronasizescale = atof(Cmd_Argv(2));
3572 else if (!strcmp(Cmd_Argv(1), "ambient"))
3574 if (Cmd_Argc() != 3)
3576 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3579 ambientscale = atof(Cmd_Argv(2));
3581 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3583 if (Cmd_Argc() != 3)
3585 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3588 diffusescale = atof(Cmd_Argv(2));
3590 else if (!strcmp(Cmd_Argv(1), "specular"))
3592 if (Cmd_Argc() != 3)
3594 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3597 specularscale = atof(Cmd_Argv(2));
3599 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3601 if (Cmd_Argc() != 3)
3603 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3606 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3608 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3610 if (Cmd_Argc() != 3)
3612 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3615 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3619 Con_Print("usage: r_editlights_edit [property] [value]\n");
3620 Con_Print("Selected light's properties:\n");
3621 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3622 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3623 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3624 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3625 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3626 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3627 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3628 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3629 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3630 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3631 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3632 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3633 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3634 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3637 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3638 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3641 void R_Shadow_EditLights_EditAll_f(void)
3645 if (!r_editlights.integer)
3647 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3651 for (light = r_shadow_worldlightchain;light;light = light->next)
3653 R_Shadow_SelectLight(light);
3654 R_Shadow_EditLights_Edit_f();
3658 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3660 int lightnumber, lightcount;
3664 if (!r_editlights.integer)
3670 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3671 if (light == r_shadow_selectedlight)
3672 lightnumber = lightcount;
3673 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;
3674 if (r_shadow_selectedlight == NULL)
3676 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3677 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;
3678 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;
3679 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;
3680 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3681 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3682 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3683 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;
3684 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3685 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3686 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3687 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3688 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3689 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;
3690 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;
3693 void R_Shadow_EditLights_ToggleShadow_f(void)
3695 if (!r_editlights.integer)
3697 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3700 if (!r_shadow_selectedlight)
3702 Con_Print("No selected light.\n");
3705 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);
3708 void R_Shadow_EditLights_ToggleCorona_f(void)
3710 if (!r_editlights.integer)
3712 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3715 if (!r_shadow_selectedlight)
3717 Con_Print("No selected light.\n");
3720 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);
3723 void R_Shadow_EditLights_Remove_f(void)
3725 if (!r_editlights.integer)
3727 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3730 if (!r_shadow_selectedlight)
3732 Con_Print("No selected light.\n");
3735 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3736 r_shadow_selectedlight = NULL;
3739 void R_Shadow_EditLights_Help_f(void)
3742 "Documentation on r_editlights system:\n"
3744 "r_editlights : enable/disable editing mode\n"
3745 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3746 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3747 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3748 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3749 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3751 "r_editlights_help : this help\n"
3752 "r_editlights_clear : remove all lights\n"
3753 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3754 "r_editlights_save : save to .rtlights file\n"
3755 "r_editlights_spawn : create a light with default settings\n"
3756 "r_editlights_edit command : edit selected light - more documentation below\n"
3757 "r_editlights_remove : remove selected light\n"
3758 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3759 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3760 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3762 "origin x y z : set light location\n"
3763 "originx x: set x component of light location\n"
3764 "originy y: set y component of light location\n"
3765 "originz z: set z component of light location\n"
3766 "move x y z : adjust light location\n"
3767 "movex x: adjust x component of light location\n"
3768 "movey y: adjust y component of light location\n"
3769 "movez z: adjust z component of light location\n"
3770 "angles x y z : set light angles\n"
3771 "anglesx x: set x component of light angles\n"
3772 "anglesy y: set y component of light angles\n"
3773 "anglesz z: set z component of light angles\n"
3774 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3775 "radius radius : set radius (size) of light\n"
3776 "colorscale grey : multiply color of light (1 does nothing)\n"
3777 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
3778 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
3779 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
3780 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3781 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3782 "shadows 1/0 : turn on/off shadows\n"
3783 "corona n : set corona intensity\n"
3784 "coronasize n : set corona size (0-1)\n"
3785 "ambient n : set ambient intensity (0-1)\n"
3786 "diffuse n : set diffuse intensity (0-1)\n"
3787 "specular n : set specular intensity (0-1)\n"
3788 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
3789 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
3790 "<nothing> : print light properties to console\n"
3794 void R_Shadow_EditLights_CopyInfo_f(void)
3796 if (!r_editlights.integer)
3798 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
3801 if (!r_shadow_selectedlight)
3803 Con_Print("No selected light.\n");
3806 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
3807 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
3808 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
3809 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
3810 if (r_shadow_selectedlight->cubemapname)
3811 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
3813 r_shadow_bufferlight.cubemapname[0] = 0;
3814 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
3815 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
3816 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
3817 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
3818 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
3819 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
3820 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
3823 void R_Shadow_EditLights_PasteInfo_f(void)
3825 if (!r_editlights.integer)
3827 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
3830 if (!r_shadow_selectedlight)
3832 Con_Print("No selected light.\n");
3835 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);
3838 void R_Shadow_EditLights_Init(void)
3840 Cvar_RegisterVariable(&r_editlights);
3841 Cvar_RegisterVariable(&r_editlights_cursordistance);
3842 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3843 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3844 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3845 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3846 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
3847 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
3848 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)");
3849 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
3850 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
3851 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
3852 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)");
3853 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
3854 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
3855 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
3856 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
3857 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
3858 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
3859 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)");