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 int r_shadow_buffer_numshadowtrispvsbytes;
189 unsigned char *r_shadow_buffer_shadowtrispvs;
190 int r_shadow_buffer_numlighttrispvsbytes;
191 unsigned char *r_shadow_buffer_lighttrispvs;
193 // current light's cull box (copied out of an rtlight or calculated by GetLightInfo)
194 vec3_t r_shadow_rtlight_cullmins;
195 vec3_t r_shadow_rtlight_cullmaxs;
196 // current light's culling planes
197 int r_shadow_rtlight_numfrustumplanes;
198 mplane_t r_shadow_rtlight_frustumplanes[12+6+6]; // see R_Shadow_ComputeShadowCasterCullingPlanes
200 rtexturepool_t *r_shadow_texturepool;
201 rtexture_t *r_shadow_attenuation2dtexture;
202 rtexture_t *r_shadow_attenuation3dtexture;
204 // lights are reloaded when this changes
205 char r_shadow_mapname[MAX_QPATH];
207 // used only for light filters (cubemaps)
208 rtexturepool_t *r_shadow_filters_texturepool;
210 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"};
211 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"};
212 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
213 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)"};
214 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"};
215 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
216 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
217 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5", "changes attenuation texture generation (does not affect r_glsl lighting)"};
218 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1", "changes attenuation texture generation (does not affect r_glsl lighting)"};
219 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
220 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
221 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
222 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
223 cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
224 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
225 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
226 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
227 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
228 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)"};
229 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"};
230 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"};
231 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
232 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
233 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"};
234 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
235 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
236 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)"};
237 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
238 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
239 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)"};
240 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)"};
241 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
242 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
243 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
244 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
245 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
246 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
247 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
248 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
250 float r_shadow_attenpower, r_shadow_attenscale;
252 rtlight_t *r_shadow_compilingrtlight;
253 dlight_t *r_shadow_worldlightchain;
254 dlight_t *r_shadow_selectedlight;
255 dlight_t r_shadow_bufferlight;
256 vec3_t r_editlights_cursorlocation;
258 extern int con_vislines;
260 typedef struct cubemapinfo_s
267 #define MAX_CUBEMAPS 256
268 static int numcubemaps;
269 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
271 void R_Shadow_UncompileWorldLights(void);
272 void R_Shadow_ClearWorldLights(void);
273 void R_Shadow_SaveWorldLights(void);
274 void R_Shadow_LoadWorldLights(void);
275 void R_Shadow_LoadLightsFile(void);
276 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
277 void R_Shadow_EditLights_Reload_f(void);
278 void R_Shadow_ValidateCvars(void);
279 static void R_Shadow_MakeTextures(void);
281 void r_shadow_start(void)
283 // allocate vertex processing arrays
285 r_shadow_attenuation2dtexture = NULL;
286 r_shadow_attenuation3dtexture = NULL;
287 r_shadow_texturepool = NULL;
288 r_shadow_filters_texturepool = NULL;
289 R_Shadow_ValidateCvars();
290 R_Shadow_MakeTextures();
291 maxshadowtriangles = 0;
292 shadowelements = NULL;
293 maxshadowvertices = 0;
294 shadowvertex3f = NULL;
302 shadowmarklist = NULL;
304 r_shadow_buffer_numleafpvsbytes = 0;
305 r_shadow_buffer_leafpvs = NULL;
306 r_shadow_buffer_leaflist = NULL;
307 r_shadow_buffer_numsurfacepvsbytes = 0;
308 r_shadow_buffer_surfacepvs = NULL;
309 r_shadow_buffer_surfacelist = NULL;
310 r_shadow_buffer_numshadowtrispvsbytes = 0;
311 r_shadow_buffer_shadowtrispvs = NULL;
312 r_shadow_buffer_numlighttrispvsbytes = 0;
313 r_shadow_buffer_lighttrispvs = NULL;
316 void r_shadow_shutdown(void)
318 R_Shadow_UncompileWorldLights();
320 r_shadow_attenuation2dtexture = NULL;
321 r_shadow_attenuation3dtexture = NULL;
322 R_FreeTexturePool(&r_shadow_texturepool);
323 R_FreeTexturePool(&r_shadow_filters_texturepool);
324 maxshadowtriangles = 0;
326 Mem_Free(shadowelements);
327 shadowelements = NULL;
329 Mem_Free(shadowvertex3f);
330 shadowvertex3f = NULL;
333 Mem_Free(vertexupdate);
336 Mem_Free(vertexremap);
342 Mem_Free(shadowmark);
345 Mem_Free(shadowmarklist);
346 shadowmarklist = NULL;
348 r_shadow_buffer_numleafpvsbytes = 0;
349 if (r_shadow_buffer_leafpvs)
350 Mem_Free(r_shadow_buffer_leafpvs);
351 r_shadow_buffer_leafpvs = NULL;
352 if (r_shadow_buffer_leaflist)
353 Mem_Free(r_shadow_buffer_leaflist);
354 r_shadow_buffer_leaflist = NULL;
355 r_shadow_buffer_numsurfacepvsbytes = 0;
356 if (r_shadow_buffer_surfacepvs)
357 Mem_Free(r_shadow_buffer_surfacepvs);
358 r_shadow_buffer_surfacepvs = NULL;
359 if (r_shadow_buffer_surfacelist)
360 Mem_Free(r_shadow_buffer_surfacelist);
361 r_shadow_buffer_surfacelist = NULL;
362 r_shadow_buffer_numshadowtrispvsbytes = 0;
363 if (r_shadow_buffer_shadowtrispvs)
364 Mem_Free(r_shadow_buffer_shadowtrispvs);
365 r_shadow_buffer_numlighttrispvsbytes = 0;
366 if (r_shadow_buffer_lighttrispvs)
367 Mem_Free(r_shadow_buffer_lighttrispvs);
370 void r_shadow_newmap(void)
374 void R_Shadow_Help_f(void)
377 "Documentation on r_shadow system:\n"
379 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
380 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
381 "r_shadow_debuglight : render only this light number (-1 = all)\n"
382 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
383 "r_shadow_gloss2intensity : brightness of forced gloss\n"
384 "r_shadow_glossintensity : brightness of textured gloss\n"
385 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
386 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
387 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
388 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
389 "r_shadow_portallight : use portal visibility for static light precomputation\n"
390 "r_shadow_projectdistance : shadow volume projection distance\n"
391 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
392 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
393 "r_shadow_realtime_world : use high quality world lighting mode\n"
394 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
395 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
396 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
397 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
398 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
399 "r_shadow_scissor : use scissor optimization\n"
400 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
401 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
402 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
403 "r_showlighting : useful for performance testing; bright = slow!\n"
404 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
406 "r_shadow_help : this help\n"
410 void R_Shadow_Init(void)
412 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
413 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
414 Cvar_RegisterVariable(&r_shadow_debuglight);
415 Cvar_RegisterVariable(&r_shadow_gloss);
416 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
417 Cvar_RegisterVariable(&r_shadow_glossintensity);
418 Cvar_RegisterVariable(&r_shadow_glossexponent);
419 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
420 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
421 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
422 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
423 Cvar_RegisterVariable(&r_shadow_portallight);
424 Cvar_RegisterVariable(&r_shadow_projectdistance);
425 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
426 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
427 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
428 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
429 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
430 Cvar_RegisterVariable(&r_shadow_realtime_world);
431 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
432 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
433 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
434 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
435 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
436 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
437 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
438 Cvar_RegisterVariable(&r_shadow_scissor);
439 Cvar_RegisterVariable(&r_shadow_culltriangles);
440 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
441 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
442 Cvar_RegisterVariable(&r_shadow_texture3d);
443 Cvar_RegisterVariable(&gl_ext_separatestencil);
444 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
445 if (gamemode == GAME_TENEBRAE)
447 Cvar_SetValue("r_shadow_gloss", 2);
448 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
450 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
451 R_Shadow_EditLights_Init();
452 r_shadow_worldlightchain = NULL;
453 maxshadowtriangles = 0;
454 shadowelements = NULL;
455 maxshadowvertices = 0;
456 shadowvertex3f = NULL;
464 shadowmarklist = NULL;
466 r_shadow_buffer_numleafpvsbytes = 0;
467 r_shadow_buffer_leafpvs = NULL;
468 r_shadow_buffer_leaflist = NULL;
469 r_shadow_buffer_numsurfacepvsbytes = 0;
470 r_shadow_buffer_surfacepvs = NULL;
471 r_shadow_buffer_surfacelist = NULL;
472 r_shadow_buffer_shadowtrispvs = NULL;
473 r_shadow_buffer_lighttrispvs = NULL;
474 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
477 matrix4x4_t matrix_attenuationxyz =
480 {0.5, 0.0, 0.0, 0.5},
481 {0.0, 0.5, 0.0, 0.5},
482 {0.0, 0.0, 0.5, 0.5},
487 matrix4x4_t matrix_attenuationz =
490 {0.0, 0.0, 0.5, 0.5},
491 {0.0, 0.0, 0.0, 0.5},
492 {0.0, 0.0, 0.0, 0.5},
497 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
499 // make sure shadowelements is big enough for this volume
500 if (maxshadowtriangles < numtriangles)
502 maxshadowtriangles = numtriangles;
504 Mem_Free(shadowelements);
505 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
507 // make sure shadowvertex3f is big enough for this volume
508 if (maxshadowvertices < numvertices)
510 maxshadowvertices = numvertices;
512 Mem_Free(shadowvertex3f);
513 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
517 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
519 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
520 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
521 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
522 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
523 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
525 if (r_shadow_buffer_leafpvs)
526 Mem_Free(r_shadow_buffer_leafpvs);
527 if (r_shadow_buffer_leaflist)
528 Mem_Free(r_shadow_buffer_leaflist);
529 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
530 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
531 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
533 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
535 if (r_shadow_buffer_surfacepvs)
536 Mem_Free(r_shadow_buffer_surfacepvs);
537 if (r_shadow_buffer_surfacelist)
538 Mem_Free(r_shadow_buffer_surfacelist);
539 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
540 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
541 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
543 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
545 if (r_shadow_buffer_shadowtrispvs)
546 Mem_Free(r_shadow_buffer_shadowtrispvs);
547 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
548 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
550 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
552 if (r_shadow_buffer_lighttrispvs)
553 Mem_Free(r_shadow_buffer_lighttrispvs);
554 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
555 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
559 void R_Shadow_PrepareShadowMark(int numtris)
561 // make sure shadowmark is big enough for this volume
562 if (maxshadowmark < numtris)
564 maxshadowmark = numtris;
566 Mem_Free(shadowmark);
568 Mem_Free(shadowmarklist);
569 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
570 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
574 // if shadowmarkcount wrapped we clear the array and adjust accordingly
575 if (shadowmarkcount == 0)
578 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
583 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)
586 int outtriangles = 0, outvertices = 0;
589 float ratio, direction[3], projectvector[3];
591 if (projectdirection)
592 VectorScale(projectdirection, projectdistance, projectvector);
594 VectorClear(projectvector);
596 if (maxvertexupdate < innumvertices)
598 maxvertexupdate = innumvertices;
600 Mem_Free(vertexupdate);
602 Mem_Free(vertexremap);
603 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
604 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
608 if (vertexupdatenum == 0)
611 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
612 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
615 for (i = 0;i < numshadowmarktris;i++)
616 shadowmark[shadowmarktris[i]] = shadowmarkcount;
618 // create the vertices
619 if (projectdirection)
621 for (i = 0;i < numshadowmarktris;i++)
623 element = inelement3i + shadowmarktris[i] * 3;
624 for (j = 0;j < 3;j++)
626 if (vertexupdate[element[j]] != vertexupdatenum)
628 vertexupdate[element[j]] = vertexupdatenum;
629 vertexremap[element[j]] = outvertices;
630 vertex = invertex3f + element[j] * 3;
631 // project one copy of the vertex according to projectvector
632 VectorCopy(vertex, outvertex3f);
633 VectorAdd(vertex, projectvector, (outvertex3f + 3));
642 for (i = 0;i < numshadowmarktris;i++)
644 element = inelement3i + shadowmarktris[i] * 3;
645 for (j = 0;j < 3;j++)
647 if (vertexupdate[element[j]] != vertexupdatenum)
649 vertexupdate[element[j]] = vertexupdatenum;
650 vertexremap[element[j]] = outvertices;
651 vertex = invertex3f + element[j] * 3;
652 // project one copy of the vertex to the sphere radius of the light
653 // (FIXME: would projecting it to the light box be better?)
654 VectorSubtract(vertex, projectorigin, direction);
655 ratio = projectdistance / VectorLength(direction);
656 VectorCopy(vertex, outvertex3f);
657 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
665 if (r_shadow_frontsidecasting.integer)
667 for (i = 0;i < numshadowmarktris;i++)
669 int remappedelement[3];
671 const int *neighbortriangle;
673 markindex = shadowmarktris[i] * 3;
674 element = inelement3i + markindex;
675 neighbortriangle = inneighbor3i + markindex;
676 // output the front and back triangles
677 outelement3i[0] = vertexremap[element[0]];
678 outelement3i[1] = vertexremap[element[1]];
679 outelement3i[2] = vertexremap[element[2]];
680 outelement3i[3] = vertexremap[element[2]] + 1;
681 outelement3i[4] = vertexremap[element[1]] + 1;
682 outelement3i[5] = vertexremap[element[0]] + 1;
686 // output the sides (facing outward from this triangle)
687 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
689 remappedelement[0] = vertexremap[element[0]];
690 remappedelement[1] = vertexremap[element[1]];
691 outelement3i[0] = remappedelement[1];
692 outelement3i[1] = remappedelement[0];
693 outelement3i[2] = remappedelement[0] + 1;
694 outelement3i[3] = remappedelement[1];
695 outelement3i[4] = remappedelement[0] + 1;
696 outelement3i[5] = remappedelement[1] + 1;
701 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
703 remappedelement[1] = vertexremap[element[1]];
704 remappedelement[2] = vertexremap[element[2]];
705 outelement3i[0] = remappedelement[2];
706 outelement3i[1] = remappedelement[1];
707 outelement3i[2] = remappedelement[1] + 1;
708 outelement3i[3] = remappedelement[2];
709 outelement3i[4] = remappedelement[1] + 1;
710 outelement3i[5] = remappedelement[2] + 1;
715 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
717 remappedelement[0] = vertexremap[element[0]];
718 remappedelement[2] = vertexremap[element[2]];
719 outelement3i[0] = remappedelement[0];
720 outelement3i[1] = remappedelement[2];
721 outelement3i[2] = remappedelement[2] + 1;
722 outelement3i[3] = remappedelement[0];
723 outelement3i[4] = remappedelement[2] + 1;
724 outelement3i[5] = remappedelement[0] + 1;
733 for (i = 0;i < numshadowmarktris;i++)
735 int remappedelement[3];
737 const int *neighbortriangle;
739 markindex = shadowmarktris[i] * 3;
740 element = inelement3i + markindex;
741 neighbortriangle = inneighbor3i + markindex;
742 // output the front and back triangles
743 outelement3i[0] = vertexremap[element[2]];
744 outelement3i[1] = vertexremap[element[1]];
745 outelement3i[2] = vertexremap[element[0]];
746 outelement3i[3] = vertexremap[element[0]] + 1;
747 outelement3i[4] = vertexremap[element[1]] + 1;
748 outelement3i[5] = vertexremap[element[2]] + 1;
752 // output the sides (facing outward from this triangle)
753 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
755 remappedelement[0] = vertexremap[element[0]];
756 remappedelement[1] = vertexremap[element[1]];
757 outelement3i[0] = remappedelement[0];
758 outelement3i[1] = remappedelement[1];
759 outelement3i[2] = remappedelement[1] + 1;
760 outelement3i[3] = remappedelement[0];
761 outelement3i[4] = remappedelement[1] + 1;
762 outelement3i[5] = remappedelement[0] + 1;
767 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
769 remappedelement[1] = vertexremap[element[1]];
770 remappedelement[2] = vertexremap[element[2]];
771 outelement3i[0] = remappedelement[1];
772 outelement3i[1] = remappedelement[2];
773 outelement3i[2] = remappedelement[2] + 1;
774 outelement3i[3] = remappedelement[1];
775 outelement3i[4] = remappedelement[2] + 1;
776 outelement3i[5] = remappedelement[1] + 1;
781 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
783 remappedelement[0] = vertexremap[element[0]];
784 remappedelement[2] = vertexremap[element[2]];
785 outelement3i[0] = remappedelement[2];
786 outelement3i[1] = remappedelement[0];
787 outelement3i[2] = remappedelement[0] + 1;
788 outelement3i[3] = remappedelement[2];
789 outelement3i[4] = remappedelement[0] + 1;
790 outelement3i[5] = remappedelement[2] + 1;
798 *outnumvertices = outvertices;
802 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)
805 if (projectdistance < 0.1)
807 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
810 if (!numverts || !nummarktris)
812 // make sure shadowelements is big enough for this volume
813 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
814 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
815 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
816 r_refdef.stats.lights_dynamicshadowtriangles += tris;
817 R_Shadow_RenderVolume(outverts, tris, shadowvertex3f, shadowelements);
820 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)
826 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
828 tend = firsttriangle + numtris;
829 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
831 // surface box entirely inside light box, no box cull
832 if (projectdirection)
834 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
836 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
837 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
838 shadowmarklist[numshadowmark++] = t;
843 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
844 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
845 shadowmarklist[numshadowmark++] = t;
850 // surface box not entirely inside light box, cull each triangle
851 if (projectdirection)
853 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
855 v[0] = invertex3f + e[0] * 3;
856 v[1] = invertex3f + e[1] * 3;
857 v[2] = invertex3f + e[2] * 3;
858 TriangleNormal(v[0], v[1], v[2], normal);
859 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
860 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
861 shadowmarklist[numshadowmark++] = t;
866 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
868 v[0] = invertex3f + e[0] * 3;
869 v[1] = invertex3f + e[1] * 3;
870 v[2] = invertex3f + e[2] * 3;
871 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
872 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
873 shadowmarklist[numshadowmark++] = t;
879 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
881 if (r_shadow_compilingrtlight)
883 // if we're compiling an rtlight, capture the mesh
884 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
887 r_refdef.stats.lights_shadowtriangles += numtriangles;
889 R_Mesh_VertexPointer(vertex3f);
890 GL_LockArrays(0, numvertices);
891 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
893 // decrement stencil if backface is behind depthbuffer
894 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
895 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
896 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
897 // increment stencil if frontface is behind depthbuffer
898 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
899 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
901 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
906 static void R_Shadow_MakeTextures(void)
909 float v[3], intensity;
911 R_FreeTexturePool(&r_shadow_texturepool);
912 r_shadow_texturepool = R_AllocTexturePool();
913 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
914 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
915 #define ATTEN2DSIZE 64
916 #define ATTEN3DSIZE 32
917 data = (unsigned char *)Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
918 for (y = 0;y < ATTEN2DSIZE;y++)
920 for (x = 0;x < ATTEN2DSIZE;x++)
922 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
923 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
925 intensity = 1.0f - sqrt(DotProduct(v, v));
927 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
928 d = (int)bound(0, intensity, 255);
929 data[(y*ATTEN2DSIZE+x)*4+0] = d;
930 data[(y*ATTEN2DSIZE+x)*4+1] = d;
931 data[(y*ATTEN2DSIZE+x)*4+2] = d;
932 data[(y*ATTEN2DSIZE+x)*4+3] = d;
935 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
936 if (r_shadow_texture3d.integer && gl_texture3d)
938 for (z = 0;z < ATTEN3DSIZE;z++)
940 for (y = 0;y < ATTEN3DSIZE;y++)
942 for (x = 0;x < ATTEN3DSIZE;x++)
944 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
945 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
946 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
947 intensity = 1.0f - sqrt(DotProduct(v, v));
949 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
950 d = (int)bound(0, intensity, 255);
951 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
952 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
953 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
954 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
958 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
963 void R_Shadow_ValidateCvars(void)
965 if (r_shadow_texture3d.integer && !gl_texture3d)
966 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
967 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
968 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
969 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
970 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
973 // light currently being rendered
974 rtlight_t *r_shadow_rtlight;
976 // this is the location of the light in entity space
977 vec3_t r_shadow_entitylightorigin;
978 // this transforms entity coordinates to light filter cubemap coordinates
979 // (also often used for other purposes)
980 matrix4x4_t r_shadow_entitytolight;
981 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
982 // of attenuation texturing in full 3D (Z result often ignored)
983 matrix4x4_t r_shadow_entitytoattenuationxyz;
984 // this transforms only the Z to S, and T is always 0.5
985 matrix4x4_t r_shadow_entitytoattenuationz;
987 void R_Shadow_RenderMode_Begin(void)
989 R_Shadow_ValidateCvars();
991 if (!r_shadow_attenuation2dtexture
992 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
993 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
994 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
995 R_Shadow_MakeTextures();
998 R_Mesh_ColorPointer(NULL);
999 R_Mesh_ResetTextureState();
1000 GL_BlendFunc(GL_ONE, GL_ZERO);
1002 GL_DepthMask(false);
1003 GL_Color(0, 0, 0, 1);
1004 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1006 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1008 if (gl_ext_separatestencil.integer)
1009 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
1010 else if (gl_ext_stenciltwoside.integer)
1011 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
1013 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
1015 if (r_glsl.integer && gl_support_fragment_shader)
1016 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1017 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1018 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1020 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1023 void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
1025 r_shadow_rtlight = rtlight;
1028 void R_Shadow_RenderMode_Reset(void)
1031 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1033 qglUseProgramObjectARB(0);CHECKGLERROR
1035 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1037 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1039 R_Mesh_ColorPointer(NULL);
1040 R_Mesh_ResetTextureState();
1042 GL_DepthMask(false);
1043 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1044 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1045 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1046 qglStencilMask(~0);CHECKGLERROR
1047 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1048 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1049 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
1050 GL_Color(1, 1, 1, 1);
1051 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
1052 GL_BlendFunc(GL_ONE, GL_ZERO);
1055 void R_Shadow_RenderMode_StencilShadowVolumes(void)
1058 R_Shadow_RenderMode_Reset();
1059 GL_ColorMask(0, 0, 0, 0);
1060 qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1061 qglDepthFunc(GL_LESS);CHECKGLERROR
1062 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1063 r_shadow_rendermode = r_shadow_shadowingrendermode;
1064 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SEPARATESTENCIL)
1066 GL_CullFace(GL_NONE);
1067 qglStencilOpSeparate(GL_BACK, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR // quake is backwards, this is front faces
1068 qglStencilOpSeparate(GL_FRONT, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR // quake is backwards, this is back faces
1070 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1072 GL_CullFace(GL_NONE);
1073 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1074 qglActiveStencilFaceEXT(GL_BACK);CHECKGLERROR // quake is backwards, this is front faces
1075 qglStencilMask(~0);CHECKGLERROR
1076 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1077 qglActiveStencilFaceEXT(GL_FRONT);CHECKGLERROR // quake is backwards, this is back faces
1078 qglStencilMask(~0);CHECKGLERROR
1079 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1081 GL_Clear(GL_STENCIL_BUFFER_BIT);
1082 r_refdef.stats.lights_clears++;
1085 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
1088 R_Shadow_RenderMode_Reset();
1089 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1092 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1096 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1097 // only draw light where this geometry was already rendered AND the
1098 // stencil is 128 (values other than this mean shadow)
1099 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1101 r_shadow_rendermode = r_shadow_lightingrendermode;
1102 // do global setup needed for the chosen lighting mode
1103 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1105 R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
1106 R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
1107 R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
1108 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_rtlight->currentcubemap)); // light filter
1109 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
1110 R_Mesh_TexBind(5, R_GetTexture(r_texture_white)); // pants
1111 R_Mesh_TexBind(6, R_GetTexture(r_texture_white)); // shirt
1112 R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); // lightmap
1113 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); // deluxemap
1114 R_Mesh_TexBind(9, R_GetTexture(r_texture_black)); // glow
1115 //R_Mesh_TexMatrix(3, r_shadow_entitytolight); // light filter matrix
1116 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1117 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1122 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1125 R_Shadow_RenderMode_Reset();
1126 GL_BlendFunc(GL_ONE, GL_ONE);
1127 GL_DepthTest(r_showshadowvolumes.integer < 2);
1128 GL_Color(0.0, 0.0125 * r_view.colorscale, 0.1 * r_view.colorscale, 1);
1129 qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1130 GL_CullFace(GL_NONE);
1131 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1134 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1137 R_Shadow_RenderMode_Reset();
1138 GL_BlendFunc(GL_ONE, GL_ONE);
1139 GL_DepthTest(r_showlighting.integer < 2);
1140 GL_Color(0.1 * r_view.colorscale, 0.0125 * r_view.colorscale, 0, 1);
1143 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1147 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1148 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1150 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1153 void R_Shadow_RenderMode_End(void)
1156 R_Shadow_RenderMode_Reset();
1157 R_Shadow_RenderMode_ActiveLight(NULL);
1159 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1160 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1163 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1165 int i, ix1, iy1, ix2, iy2;
1166 float x1, y1, x2, y2;
1169 mplane_t planes[11];
1170 float vertex3f[256*3];
1172 // if view is inside the light box, just say yes it's visible
1173 if (BoxesOverlap(r_view.origin, r_view.origin, mins, maxs))
1175 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1179 // create a temporary brush describing the area the light can affect in worldspace
1180 VectorNegate(r_view.frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -r_view.frustum[0].dist;
1181 VectorNegate(r_view.frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -r_view.frustum[1].dist;
1182 VectorNegate(r_view.frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -r_view.frustum[2].dist;
1183 VectorNegate(r_view.frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -r_view.frustum[3].dist;
1184 VectorNegate(r_view.frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -r_view.frustum[4].dist;
1185 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1186 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1187 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1188 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1189 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1190 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1192 // turn the brush into a mesh
1193 memset(&mesh, 0, sizeof(rmesh_t));
1194 mesh.maxvertices = 256;
1195 mesh.vertex3f = vertex3f;
1196 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1197 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1199 // if that mesh is empty, the light is not visible at all
1200 if (!mesh.numvertices)
1203 if (!r_shadow_scissor.integer)
1206 // if that mesh is not empty, check what area of the screen it covers
1207 x1 = y1 = x2 = y2 = 0;
1209 //Con_Printf("%i vertices to transform...\n", mesh.numvertices);
1210 for (i = 0;i < mesh.numvertices;i++)
1212 VectorCopy(mesh.vertex3f + i * 3, v);
1213 GL_TransformToScreen(v, v2);
1214 //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]);
1217 if (x1 > v2[0]) x1 = v2[0];
1218 if (x2 < v2[0]) x2 = v2[0];
1219 if (y1 > v2[1]) y1 = v2[1];
1220 if (y2 < v2[1]) y2 = v2[1];
1229 // now convert the scissor rectangle to integer screen coordinates
1230 ix1 = (int)(x1 - 1.0f);
1231 iy1 = (int)(y1 - 1.0f);
1232 ix2 = (int)(x2 + 1.0f);
1233 iy2 = (int)(y2 + 1.0f);
1234 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1236 // clamp it to the screen
1237 if (ix1 < r_view.x) ix1 = r_view.x;
1238 if (iy1 < r_view.y) iy1 = r_view.y;
1239 if (ix2 > r_view.x + r_view.width) ix2 = r_view.x + r_view.width;
1240 if (iy2 > r_view.y + r_view.height) iy2 = r_view.y + r_view.height;
1242 // if it is inside out, it's not visible
1243 if (ix2 <= ix1 || iy2 <= iy1)
1246 // the light area is visible, set up the scissor rectangle
1247 GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1248 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1249 //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1250 r_refdef.stats.lights_scissored++;
1254 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1256 float *vertex3f = rsurface_vertex3f + 3 * firstvertex;
1257 float *normal3f = rsurface_normal3f + 3 * firstvertex;
1258 float *color4f = rsurface_array_color4f + 4 * firstvertex;
1259 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1260 if (r_textureunits.integer >= 3)
1262 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1264 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1265 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1266 if ((dot = DotProduct(n, v)) < 0)
1268 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1269 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]);
1270 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]);
1271 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]);
1272 if (r_refdef.fogenabled)
1274 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1275 VectorScale(color4f, f, color4f);
1279 VectorClear(color4f);
1283 else if (r_textureunits.integer >= 2)
1285 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1287 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1288 if ((dist = fabs(v[2])) < 1)
1290 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1291 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1292 if ((dot = DotProduct(n, v)) < 0)
1294 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1295 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1296 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1297 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1301 color4f[0] = ambientcolor[0] * distintensity;
1302 color4f[1] = ambientcolor[1] * distintensity;
1303 color4f[2] = ambientcolor[2] * distintensity;
1305 if (r_refdef.fogenabled)
1307 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1308 VectorScale(color4f, f, color4f);
1312 VectorClear(color4f);
1318 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1320 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1321 if ((dist = DotProduct(v, v)) < 1)
1324 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1325 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1326 if ((dot = DotProduct(n, v)) < 0)
1328 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1329 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1330 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1331 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1335 color4f[0] = ambientcolor[0] * distintensity;
1336 color4f[1] = ambientcolor[1] * distintensity;
1337 color4f[2] = ambientcolor[2] * distintensity;
1339 if (r_refdef.fogenabled)
1341 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1342 VectorScale(color4f, f, color4f);
1346 VectorClear(color4f);
1352 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1354 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1357 float *out3f = rsurface_array_texcoord3f + 3 * firstvertex;
1358 const float *vertex3f = rsurface_vertex3f + 3 * firstvertex;
1359 const float *svector3f = rsurface_svector3f + 3 * firstvertex;
1360 const float *tvector3f = rsurface_tvector3f + 3 * firstvertex;
1361 const float *normal3f = rsurface_normal3f + 3 * firstvertex;
1363 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1365 VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1366 // the cubemap normalizes this for us
1367 out3f[0] = DotProduct(svector3f, lightdir);
1368 out3f[1] = DotProduct(tvector3f, lightdir);
1369 out3f[2] = DotProduct(normal3f, lightdir);
1373 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1376 float *out3f = rsurface_array_texcoord3f + 3 * firstvertex;
1377 const float *vertex3f = rsurface_vertex3f + 3 * firstvertex;
1378 const float *svector3f = rsurface_svector3f + 3 * firstvertex;
1379 const float *tvector3f = rsurface_tvector3f + 3 * firstvertex;
1380 const float *normal3f = rsurface_normal3f + 3 * firstvertex;
1381 float lightdir[3], eyedir[3], halfdir[3];
1382 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1384 VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1385 VectorNormalize(lightdir);
1386 VectorSubtract(rsurface_modelorg, vertex3f, eyedir);
1387 VectorNormalize(eyedir);
1388 VectorAdd(lightdir, eyedir, halfdir);
1389 // the cubemap normalizes this for us
1390 out3f[0] = DotProduct(svector3f, halfdir);
1391 out3f[1] = DotProduct(tvector3f, halfdir);
1392 out3f[2] = DotProduct(normal3f, halfdir);
1396 static void R_Shadow_RenderLighting_VisibleLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i, 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)
1398 // used to display how many times a surface is lit for level design purposes
1399 GL_Color(0.1 * r_view.colorscale, 0.025 * r_view.colorscale, 0, 1);
1400 R_Mesh_ColorPointer(NULL);
1401 R_Mesh_ResetTextureState();
1402 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
1405 static void R_Shadow_RenderLighting_Light_GLSL(int firstvertex, int numvertices, int numtriangles, const int *element3i, 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)
1407 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1408 R_SetupSurfaceShader(lightcolorbase, false);
1409 R_Mesh_TexCoordPointer(0, 2, rsurface_model->surfmesh.data_texcoordtexture2f);
1410 R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
1411 R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
1412 R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
1413 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1415 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1417 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
1418 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1420 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1424 static void R_Shadow_RenderLighting_Light_Dot3_Finalize(int firstvertex, int numvertices, int numtriangles, const int *element3i, float r, float g, float b)
1426 // shared final code for all the dot3 layers
1428 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1429 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1431 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1432 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
1436 static void R_Shadow_RenderLighting_Light_Dot3_AmbientPass(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
1439 // colorscale accounts for how much we multiply the brightness
1442 // mult is how many times the final pass of the lighting will be
1443 // performed to get more brightness than otherwise possible.
1445 // Limit mult to 64 for sanity sake.
1447 if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1449 // 3 3D combine path (Geforce3, Radeon 8500)
1450 memset(&m, 0, sizeof(m));
1451 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1452 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1453 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1454 m.tex[1] = R_GetTexture(basetexture);
1455 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1456 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1457 m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1458 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1459 m.texmatrix[2] = r_shadow_entitytolight;
1460 GL_BlendFunc(GL_ONE, GL_ONE);
1462 else if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1464 // 2 3D combine path (Geforce3, original Radeon)
1465 memset(&m, 0, sizeof(m));
1466 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1467 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1468 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1469 m.tex[1] = R_GetTexture(basetexture);
1470 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1471 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1472 GL_BlendFunc(GL_ONE, GL_ONE);
1474 else if (r_textureunits.integer >= 4 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1476 // 4 2D combine path (Geforce3, Radeon 8500)
1477 memset(&m, 0, sizeof(m));
1478 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1479 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1480 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1481 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1482 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1483 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1484 m.tex[2] = R_GetTexture(basetexture);
1485 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1486 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1487 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1489 m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1490 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1491 m.texmatrix[3] = r_shadow_entitytolight;
1493 GL_BlendFunc(GL_ONE, GL_ONE);
1495 else if (r_textureunits.integer >= 3 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1497 // 3 2D combine path (Geforce3, original Radeon)
1498 memset(&m, 0, sizeof(m));
1499 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1500 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1501 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1502 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1503 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1504 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1505 m.tex[2] = R_GetTexture(basetexture);
1506 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1507 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1508 GL_BlendFunc(GL_ONE, GL_ONE);
1512 // 2/2/2 2D combine path (any dot3 card)
1513 memset(&m, 0, sizeof(m));
1514 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1515 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1516 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1517 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1518 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1519 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1520 R_Mesh_TextureState(&m);
1521 GL_ColorMask(0,0,0,1);
1522 GL_BlendFunc(GL_ONE, GL_ZERO);
1523 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
1526 memset(&m, 0, sizeof(m));
1527 m.tex[0] = R_GetTexture(basetexture);
1528 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1529 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1530 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1532 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1533 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1534 m.texmatrix[1] = r_shadow_entitytolight;
1536 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1538 // this final code is shared
1539 R_Mesh_TextureState(&m);
1540 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1543 static void R_Shadow_RenderLighting_Light_Dot3_DiffusePass(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolorbase, rtexture_t *basetexture, rtexture_t *normalmaptexture, float colorscale)
1546 // colorscale accounts for how much we multiply the brightness
1549 // mult is how many times the final pass of the lighting will be
1550 // performed to get more brightness than otherwise possible.
1552 // Limit mult to 64 for sanity sake.
1554 // generate normalization cubemap texcoords
1555 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1556 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1558 // 3/2 3D combine path (Geforce3, Radeon 8500)
1559 memset(&m, 0, sizeof(m));
1560 m.tex[0] = R_GetTexture(normalmaptexture);
1561 m.texcombinergb[0] = GL_REPLACE;
1562 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1563 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1564 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1565 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1566 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1567 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1568 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1569 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1570 R_Mesh_TextureState(&m);
1571 GL_ColorMask(0,0,0,1);
1572 GL_BlendFunc(GL_ONE, GL_ZERO);
1573 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
1576 memset(&m, 0, sizeof(m));
1577 m.tex[0] = R_GetTexture(basetexture);
1578 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1579 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1580 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1582 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1583 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1584 m.texmatrix[1] = r_shadow_entitytolight;
1586 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1588 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1590 // 1/2/2 3D combine path (original Radeon)
1591 memset(&m, 0, sizeof(m));
1592 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1593 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1594 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1595 R_Mesh_TextureState(&m);
1596 GL_ColorMask(0,0,0,1);
1597 GL_BlendFunc(GL_ONE, GL_ZERO);
1598 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
1601 memset(&m, 0, sizeof(m));
1602 m.tex[0] = R_GetTexture(normalmaptexture);
1603 m.texcombinergb[0] = GL_REPLACE;
1604 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1605 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1606 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1607 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1608 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1609 R_Mesh_TextureState(&m);
1610 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1611 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
1614 memset(&m, 0, sizeof(m));
1615 m.tex[0] = R_GetTexture(basetexture);
1616 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1617 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1618 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1620 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1621 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1622 m.texmatrix[1] = r_shadow_entitytolight;
1624 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1626 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1628 // 2/2 3D combine path (original Radeon)
1629 memset(&m, 0, sizeof(m));
1630 m.tex[0] = R_GetTexture(normalmaptexture);
1631 m.texcombinergb[0] = GL_REPLACE;
1632 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1633 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1634 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1635 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1636 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1637 R_Mesh_TextureState(&m);
1638 GL_ColorMask(0,0,0,1);
1639 GL_BlendFunc(GL_ONE, GL_ZERO);
1640 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
1643 memset(&m, 0, sizeof(m));
1644 m.tex[0] = R_GetTexture(basetexture);
1645 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1646 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1647 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1648 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1649 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1650 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1652 else if (r_textureunits.integer >= 4)
1654 // 4/2 2D combine path (Geforce3, Radeon 8500)
1655 memset(&m, 0, sizeof(m));
1656 m.tex[0] = R_GetTexture(normalmaptexture);
1657 m.texcombinergb[0] = GL_REPLACE;
1658 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1659 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1660 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1661 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1662 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1663 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1664 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1665 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1666 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1667 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1668 m.texmatrix[3] = r_shadow_entitytoattenuationz;
1669 R_Mesh_TextureState(&m);
1670 GL_ColorMask(0,0,0,1);
1671 GL_BlendFunc(GL_ONE, GL_ZERO);
1672 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
1675 memset(&m, 0, sizeof(m));
1676 m.tex[0] = R_GetTexture(basetexture);
1677 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1678 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1679 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1681 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1682 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1683 m.texmatrix[1] = r_shadow_entitytolight;
1685 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1689 // 2/2/2 2D combine path (any dot3 card)
1690 memset(&m, 0, sizeof(m));
1691 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1692 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1693 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1694 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1695 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1696 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1697 R_Mesh_TextureState(&m);
1698 GL_ColorMask(0,0,0,1);
1699 GL_BlendFunc(GL_ONE, GL_ZERO);
1700 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
1703 memset(&m, 0, sizeof(m));
1704 m.tex[0] = R_GetTexture(normalmaptexture);
1705 m.texcombinergb[0] = GL_REPLACE;
1706 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1707 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1708 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1709 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1710 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1711 R_Mesh_TextureState(&m);
1712 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1713 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
1716 memset(&m, 0, sizeof(m));
1717 m.tex[0] = R_GetTexture(basetexture);
1718 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1719 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1720 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1722 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1723 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1724 m.texmatrix[1] = r_shadow_entitytolight;
1726 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1728 // this final code is shared
1729 R_Mesh_TextureState(&m);
1730 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1733 static void R_Shadow_RenderLighting_Light_Dot3_SpecularPass(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolorbase, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale)
1735 float glossexponent;
1737 // FIXME: detect blendsquare!
1738 //if (!gl_support_blendsquare)
1741 // generate normalization cubemap texcoords
1742 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1743 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1745 // 2/0/0/1/2 3D combine blendsquare path
1746 memset(&m, 0, sizeof(m));
1747 m.tex[0] = R_GetTexture(normalmaptexture);
1748 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1749 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1750 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1751 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1752 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1753 R_Mesh_TextureState(&m);
1754 GL_ColorMask(0,0,0,1);
1755 // this squares the result
1756 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1757 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
1759 // second and third pass
1760 R_Mesh_ResetTextureState();
1761 // square alpha in framebuffer a few times to make it shiny
1762 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1763 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1764 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
1767 memset(&m, 0, sizeof(m));
1768 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1769 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1770 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1771 R_Mesh_TextureState(&m);
1772 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1773 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
1776 memset(&m, 0, sizeof(m));
1777 m.tex[0] = R_GetTexture(glosstexture);
1778 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1779 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1780 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1782 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1783 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1784 m.texmatrix[1] = r_shadow_entitytolight;
1786 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1788 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1790 // 2/0/0/2 3D combine blendsquare path
1791 memset(&m, 0, sizeof(m));
1792 m.tex[0] = R_GetTexture(normalmaptexture);
1793 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1794 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1795 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1796 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1797 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1798 R_Mesh_TextureState(&m);
1799 GL_ColorMask(0,0,0,1);
1800 // this squares the result
1801 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1802 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
1804 // second and third pass
1805 R_Mesh_ResetTextureState();
1806 // square alpha in framebuffer a few times to make it shiny
1807 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1808 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1809 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
1812 memset(&m, 0, sizeof(m));
1813 m.tex[0] = R_GetTexture(glosstexture);
1814 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1815 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1816 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1817 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1818 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1819 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1823 // 2/0/0/2/2 2D combine blendsquare path
1824 memset(&m, 0, sizeof(m));
1825 m.tex[0] = R_GetTexture(normalmaptexture);
1826 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1827 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1828 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1829 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1830 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1831 R_Mesh_TextureState(&m);
1832 GL_ColorMask(0,0,0,1);
1833 // this squares the result
1834 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1835 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
1837 // second and third pass
1838 R_Mesh_ResetTextureState();
1839 // square alpha in framebuffer a few times to make it shiny
1840 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1841 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1842 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
1845 memset(&m, 0, sizeof(m));
1846 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1847 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1848 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1849 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1850 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1851 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1852 R_Mesh_TextureState(&m);
1853 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1854 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i);
1857 memset(&m, 0, sizeof(m));
1858 m.tex[0] = R_GetTexture(glosstexture);
1859 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1860 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1861 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1863 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1864 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1865 m.texmatrix[1] = r_shadow_entitytolight;
1867 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1869 // this final code is shared
1870 R_Mesh_TextureState(&m);
1871 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1874 static void R_Shadow_RenderLighting_Light_Dot3(int firstvertex, int numvertices, int numtriangles, const int *element3i, 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)
1876 // ARB path (any Geforce, any Radeon)
1877 qboolean doambient = r_shadow_rtlight->ambientscale > 0;
1878 qboolean dodiffuse = r_shadow_rtlight->diffusescale > 0;
1879 qboolean dospecular = specularscale > 0;
1880 if (!doambient && !dodiffuse && !dospecular)
1882 R_Mesh_ColorPointer(NULL);
1884 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, lightcolorbase, basetexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1886 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, lightcolorbase, basetexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1890 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, lightcolorpants, pantstexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1892 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, lightcolorpants, pantstexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1897 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, lightcolorshirt, shirttexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1899 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, lightcolorshirt, shirttexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1902 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, numtriangles, element3i, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale);
1905 void R_Shadow_RenderLighting_Light_Vertex_Pass(const model_t *model, int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
1912 int newnumtriangles;
1916 int newelements[3072];
1917 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
1918 for (renders = 0;renders < 64;renders++)
1923 newnumtriangles = 0;
1925 // due to low fillrate on the cards this vertex lighting path is
1926 // designed for, we manually cull all triangles that do not
1927 // contain a lit vertex
1928 // this builds batches of triangles from multiple surfaces and
1929 // renders them at once
1930 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
1932 if (VectorLength2(rsurface_array_color4f + e[0] * 4) + VectorLength2(rsurface_array_color4f + e[1] * 4) + VectorLength2(rsurface_array_color4f + e[2] * 4) >= 0.01)
1934 if (newnumtriangles)
1936 newfirstvertex = min(newfirstvertex, e[0]);
1937 newlastvertex = max(newlastvertex, e[0]);
1941 newfirstvertex = e[0];
1942 newlastvertex = e[0];
1944 newfirstvertex = min(newfirstvertex, e[1]);
1945 newlastvertex = max(newlastvertex, e[1]);
1946 newfirstvertex = min(newfirstvertex, e[2]);
1947 newlastvertex = max(newlastvertex, e[2]);
1953 if (newnumtriangles >= 1024)
1955 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements);
1956 newnumtriangles = 0;
1962 if (newnumtriangles >= 1)
1964 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements);
1967 // if we couldn't find any lit triangles, exit early
1970 // now reduce the intensity for the next overbright pass
1971 // we have to clamp to 0 here incase the drivers have improper
1972 // handling of negative colors
1973 // (some old drivers even have improper handling of >1 color)
1975 for (i = 0, c = rsurface_array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
1977 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
1979 c[0] = max(0, c[0] - 1);
1980 c[1] = max(0, c[1] - 1);
1981 c[2] = max(0, c[2] - 1);
1993 static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, 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)
1995 // OpenGL 1.1 path (anything)
1996 model_t *model = rsurface_entity->model;
1997 float ambientcolorbase[3], diffusecolorbase[3];
1998 float ambientcolorpants[3], diffusecolorpants[3];
1999 float ambientcolorshirt[3], diffusecolorshirt[3];
2001 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorbase);
2002 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorbase);
2003 VectorScale(lightcolorpants, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorpants);
2004 VectorScale(lightcolorpants, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorpants);
2005 VectorScale(lightcolorshirt, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorshirt);
2006 VectorScale(lightcolorshirt, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorshirt);
2007 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2008 R_Mesh_ColorPointer(rsurface_array_color4f);
2009 memset(&m, 0, sizeof(m));
2010 m.tex[0] = R_GetTexture(basetexture);
2011 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
2012 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
2013 if (r_textureunits.integer >= 2)
2016 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2017 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2018 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2019 if (r_textureunits.integer >= 3)
2021 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2022 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2023 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2024 m.pointer_texcoord3f[2] = rsurface_vertex3f;
2027 R_Mesh_TextureState(&m);
2028 R_Mesh_TexBind(0, R_GetTexture(basetexture));
2029 R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2032 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2033 R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2037 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2038 R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2042 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2044 // FIXME: support MATERIALFLAG_NODEPTHTEST
2045 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2046 // calculate colors to render this texture with
2047 lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * rsurface_entity->colormod[0] * rsurface_texture->currentalpha;
2048 lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * rsurface_entity->colormod[1] * rsurface_texture->currentalpha;
2049 lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * rsurface_entity->colormod[2] * rsurface_texture->currentalpha;
2050 if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) + (r_shadow_rtlight->specularscale * rsurface_texture->specularscale) * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2052 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
2053 GL_CullFace((rsurface_texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
2054 if (rsurface_texture->colormapping)
2056 qboolean dopants = rsurface_texture->currentskinframe->pants != NULL && VectorLength2(rsurface_entity->colormap_pantscolor) >= (1.0f / 1048576.0f);
2057 qboolean doshirt = rsurface_texture->currentskinframe->shirt != NULL && VectorLength2(rsurface_entity->colormap_shirtcolor) >= (1.0f / 1048576.0f);
2060 lightcolorpants[0] = lightcolorbase[0] * rsurface_entity->colormap_pantscolor[0];
2061 lightcolorpants[1] = lightcolorbase[1] * rsurface_entity->colormap_pantscolor[1];
2062 lightcolorpants[2] = lightcolorbase[2] * rsurface_entity->colormap_pantscolor[2];
2065 VectorClear(lightcolorpants);
2068 lightcolorshirt[0] = lightcolorbase[0] * rsurface_entity->colormap_shirtcolor[0];
2069 lightcolorshirt[1] = lightcolorbase[1] * rsurface_entity->colormap_shirtcolor[1];
2070 lightcolorshirt[2] = lightcolorbase[2] * rsurface_entity->colormap_shirtcolor[2];
2073 VectorClear(lightcolorshirt);
2074 switch (r_shadow_rendermode)
2076 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2077 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2078 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, numtriangles, element3i, 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);
2080 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2081 R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, numtriangles, element3i, 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);
2083 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2084 R_Shadow_RenderLighting_Light_Dot3(firstvertex, numvertices, numtriangles, element3i, 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);
2086 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2087 R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i, 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);
2090 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2096 switch (r_shadow_rendermode)
2098 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2099 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2100 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, numtriangles, element3i, 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);
2102 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2103 R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, numtriangles, element3i, 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);
2105 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2106 R_Shadow_RenderLighting_Light_Dot3(firstvertex, numvertices, numtriangles, element3i, 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);
2108 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2109 R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i, 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);
2112 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2118 void R_RTLight_Update(rtlight_t *rtlight, int isstatic, matrix4x4_t *matrix, vec3_t color, int style, const char *cubemapname, qboolean shadow, vec_t corona, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
2120 matrix4x4_t tempmatrix = *matrix;
2121 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2123 // if this light has been compiled before, free the associated data
2124 R_RTLight_Uncompile(rtlight);
2126 // clear it completely to avoid any lingering data
2127 memset(rtlight, 0, sizeof(*rtlight));
2129 // copy the properties
2130 rtlight->matrix_lighttoworld = tempmatrix;
2131 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2132 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2133 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2134 VectorCopy(color, rtlight->color);
2135 rtlight->cubemapname[0] = 0;
2136 if (cubemapname && cubemapname[0])
2137 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2138 rtlight->shadow = shadow;
2139 rtlight->corona = corona;
2140 rtlight->style = style;
2141 rtlight->isstatic = isstatic;
2142 rtlight->coronasizescale = coronasizescale;
2143 rtlight->ambientscale = ambientscale;
2144 rtlight->diffusescale = diffusescale;
2145 rtlight->specularscale = specularscale;
2146 rtlight->flags = flags;
2148 // compute derived data
2149 //rtlight->cullradius = rtlight->radius;
2150 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2151 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2152 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2153 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2154 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2155 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2156 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2159 // compiles rtlight geometry
2160 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2161 void R_RTLight_Compile(rtlight_t *rtlight)
2164 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2165 int lighttris, shadowtris, shadowmeshes, shadowmeshtris;
2166 entity_render_t *ent = r_refdef.worldentity;
2167 model_t *model = r_refdef.worldmodel;
2168 unsigned char *data;
2170 // compile the light
2171 rtlight->compiled = true;
2172 rtlight->static_numleafs = 0;
2173 rtlight->static_numleafpvsbytes = 0;
2174 rtlight->static_leaflist = NULL;
2175 rtlight->static_leafpvs = NULL;
2176 rtlight->static_numsurfaces = 0;
2177 rtlight->static_surfacelist = NULL;
2178 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2179 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2180 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2181 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2182 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2183 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2185 if (model && model->GetLightInfo)
2187 // this variable must be set for the CompileShadowVolume code
2188 r_shadow_compilingrtlight = rtlight;
2189 R_Shadow_EnlargeLeafSurfaceTrisBuffer(model->brush.num_leafs, model->num_surfaces, model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles, model->surfmesh.num_triangles);
2190 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, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs);
2191 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2192 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2193 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2194 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2195 rtlight->static_numsurfaces = numsurfaces;
2196 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2197 rtlight->static_numleafs = numleafs;
2198 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2199 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2200 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2201 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2202 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2203 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2204 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2205 if (rtlight->static_numsurfaces)
2206 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2207 if (rtlight->static_numleafs)
2208 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2209 if (rtlight->static_numleafpvsbytes)
2210 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2211 if (rtlight->static_numshadowtrispvsbytes)
2212 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2213 if (rtlight->static_numlighttrispvsbytes)
2214 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2215 if (model->CompileShadowVolume && rtlight->shadow)
2216 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2217 // now we're done compiling the rtlight
2218 r_shadow_compilingrtlight = NULL;
2222 // use smallest available cullradius - box radius or light radius
2223 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2224 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2228 if (rtlight->static_meshchain_shadow)
2231 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2234 shadowmeshtris += mesh->numtriangles;
2239 if (rtlight->static_numlighttrispvsbytes)
2240 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2241 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2245 if (rtlight->static_numlighttrispvsbytes)
2246 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2247 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2250 if (developer.integer >= 10)
2251 Con_Printf("static light built: %f %f %f : %f %f %f box, %i light triangles, %i shadow triangles, %i compiled 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], lighttris, shadowtris, shadowmeshtris, shadowmeshes);
2254 void R_RTLight_Uncompile(rtlight_t *rtlight)
2256 if (rtlight->compiled)
2258 if (rtlight->static_meshchain_shadow)
2259 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2260 rtlight->static_meshchain_shadow = NULL;
2261 // these allocations are grouped
2262 if (rtlight->static_surfacelist)
2263 Mem_Free(rtlight->static_surfacelist);
2264 rtlight->static_numleafs = 0;
2265 rtlight->static_numleafpvsbytes = 0;
2266 rtlight->static_leaflist = NULL;
2267 rtlight->static_leafpvs = NULL;
2268 rtlight->static_numsurfaces = 0;
2269 rtlight->static_surfacelist = NULL;
2270 rtlight->static_numshadowtrispvsbytes = 0;
2271 rtlight->static_shadowtrispvs = NULL;
2272 rtlight->static_numlighttrispvsbytes = 0;
2273 rtlight->static_lighttrispvs = NULL;
2274 rtlight->compiled = false;
2278 void R_Shadow_UncompileWorldLights(void)
2281 for (light = r_shadow_worldlightchain;light;light = light->next)
2282 R_RTLight_Uncompile(&light->rtlight);
2285 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2289 // reset the count of frustum planes
2290 // see r_shadow_rtlight_frustumplanes definition for how much this array
2292 r_shadow_rtlight_numfrustumplanes = 0;
2295 // generate a deformed frustum that includes the light origin, this is
2296 // used to cull shadow casting surfaces that can not possibly cast a
2297 // shadow onto the visible light-receiving surfaces, which can be a
2300 // if the light origin is onscreen the result will be 4 planes exactly
2301 // if the light origin is offscreen on only one axis the result will
2302 // be exactly 5 planes (split-side case)
2303 // if the light origin is offscreen on two axes the result will be
2304 // exactly 4 planes (stretched corner case)
2305 for (i = 0;i < 4;i++)
2307 // quickly reject standard frustum planes that put the light
2308 // origin outside the frustum
2309 if (PlaneDiff(rtlight->shadoworigin, &r_view.frustum[i]) < -0.03125)
2312 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = r_view.frustum[i];
2314 // if all the standard frustum planes were accepted, the light is onscreen
2315 // otherwise we need to generate some more planes below...
2316 if (r_shadow_rtlight_numfrustumplanes < 4)
2318 // at least one of the stock frustum planes failed, so we need to
2319 // create one or two custom planes to enclose the light origin
2320 for (i = 0;i < 4;i++)
2322 // create a plane using the view origin and light origin, and a
2323 // single point from the frustum corner set
2324 TriangleNormal(r_view.origin, r_view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2325 VectorNormalize(plane.normal);
2326 plane.dist = DotProduct(r_view.origin, plane.normal);
2327 // see if this plane is backwards and flip it if so
2328 for (j = 0;j < 4;j++)
2329 if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2333 VectorNegate(plane.normal, plane.normal);
2335 // flipped plane, test again to see if it is now valid
2336 for (j = 0;j < 4;j++)
2337 if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2339 // if the plane is still not valid, then it is dividing the
2340 // frustum and has to be rejected
2344 // we have created a valid plane, compute extra info
2345 PlaneClassify(&plane);
2347 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = plane;
2349 // if we've found 5 frustum planes then we have constructed a
2350 // proper split-side case and do not need to keep searching for
2351 // planes to enclose the light origin
2352 if (r_shadow_rtlight_numfrustumplanes == 5)
2360 for (i = 0;i < r_shadow_rtlight_numfrustumplanes;i++)
2362 plane = r_shadow_rtlight_frustumplanes[i];
2363 Con_Printf("light %p plane #%i %f %f %f : %f (%f %f %f %f %f)\n", rtlight, i, plane.normal[0], plane.normal[1], plane.normal[2], plane.dist, PlaneDiff(r_view.frustumcorner[0], &plane), PlaneDiff(r_view.frustumcorner[1], &plane), PlaneDiff(r_view.frustumcorner[2], &plane), PlaneDiff(r_view.frustumcorner[3], &plane), PlaneDiff(rtlight->shadoworigin, &plane));
2368 // now add the light-space box planes if the light box is rotated, as any
2369 // caster outside the oriented light box is irrelevant (even if it passed
2370 // the worldspace light box, which is axial)
2371 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
2373 for (i = 0;i < 6;i++)
2377 v[i >> 1] = (i & 1) ? -1 : 1;
2378 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
2379 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
2380 plane.dist = VectorNormalizeLength(plane.normal);
2381 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
2382 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = plane;
2388 // add the world-space reduced box planes
2389 for (i = 0;i < 6;i++)
2391 VectorClear(plane.normal);
2392 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
2393 plane.dist = (i & 1) ? -r_shadow_rtlight_cullmaxs[i >> 1] : r_shadow_rtlight_cullmins[i >> 1];
2394 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = plane;
2403 // reduce all plane distances to tightly fit the rtlight cull box, which
2405 VectorSet(points[0], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmins[2]);
2406 VectorSet(points[1], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmins[2]);
2407 VectorSet(points[2], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmins[2]);
2408 VectorSet(points[3], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmins[2]);
2409 VectorSet(points[4], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmaxs[2]);
2410 VectorSet(points[5], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmaxs[2]);
2411 VectorSet(points[6], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmaxs[2]);
2412 VectorSet(points[7], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmaxs[2]);
2413 oldnum = r_shadow_rtlight_numfrustumplanes;
2414 r_shadow_rtlight_numfrustumplanes = 0;
2415 for (j = 0;j < oldnum;j++)
2417 // find the nearest point on the box to this plane
2418 bestdist = DotProduct(r_shadow_rtlight_frustumplanes[j].normal, points[0]);
2419 for (i = 1;i < 8;i++)
2421 dist = DotProduct(r_shadow_rtlight_frustumplanes[j].normal, points[i]);
2422 if (bestdist > dist)
2425 Con_Printf("light %p %splane #%i %f %f %f : %f < %f\n", rtlight, r_shadow_rtlight_frustumplanes[j].dist < bestdist + 0.03125 ? "^2" : "^1", j, r_shadow_rtlight_frustumplanes[j].normal[0], r_shadow_rtlight_frustumplanes[j].normal[1], r_shadow_rtlight_frustumplanes[j].normal[2], r_shadow_rtlight_frustumplanes[j].dist, bestdist);
2426 // if the nearest point is near or behind the plane, we want this
2427 // plane, otherwise the plane is useless as it won't cull anything
2428 if (r_shadow_rtlight_frustumplanes[j].dist < bestdist + 0.03125)
2430 PlaneClassify(&r_shadow_rtlight_frustumplanes[j]);
2431 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = r_shadow_rtlight_frustumplanes[j];
2438 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2440 RSurf_ActiveWorldEntity();
2441 if (r_shadow_rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2445 for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2447 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2448 R_Mesh_VertexPointer(mesh->vertex3f);
2449 GL_LockArrays(0, mesh->numverts);
2450 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2452 // decrement stencil if backface is behind depthbuffer
2453 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
2454 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2455 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2456 // increment stencil if frontface is behind depthbuffer
2457 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2458 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2460 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2461 GL_LockArrays(0, 0);
2465 else if (numsurfaces && r_refdef.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
2468 int surfacelistindex;
2469 msurface_t *surface;
2470 R_Shadow_PrepareShadowMark(r_refdef.worldmodel->brush.shadowmesh->numtriangles);
2471 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2473 surface = r_refdef.worldmodel->data_surfaces + surfacelist[surfacelistindex];
2474 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
2475 if (CHECKPVSBIT(trispvs, t))
2476 shadowmarklist[numshadowmark++] = t;
2478 R_Shadow_VolumeFromList(r_refdef.worldmodel->brush.shadowmesh->numverts, r_refdef.worldmodel->brush.shadowmesh->numtriangles, r_refdef.worldmodel->brush.shadowmesh->vertex3f, r_refdef.worldmodel->brush.shadowmesh->element3i, r_refdef.worldmodel->brush.shadowmesh->neighbor3i, r_shadow_rtlight->shadoworigin, NULL, r_shadow_rtlight->radius + r_refdef.worldmodel->radius*2 + r_shadow_projectdistance.value, numshadowmark, shadowmarklist);
2480 else if (numsurfaces)
2481 r_refdef.worldmodel->DrawShadowVolume(r_refdef.worldentity, r_shadow_rtlight->shadoworigin, NULL, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs);
2484 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
2486 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2487 vec_t relativeshadowradius;
2488 RSurf_ActiveModelEntity(ent, false, false);
2489 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, relativeshadoworigin);
2490 relativeshadowradius = r_shadow_rtlight->radius / ent->scale;
2491 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2492 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2493 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2494 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2495 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2496 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2497 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2500 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2502 // set up properties for rendering light onto this entity
2503 RSurf_ActiveModelEntity(ent, true, true);
2504 Matrix4x4_Concat(&r_shadow_entitytolight, &r_shadow_rtlight->matrix_worldtolight, &ent->matrix);
2505 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2506 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2507 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2508 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2509 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2512 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2514 if (!r_refdef.worldmodel->DrawLight)
2517 // set up properties for rendering light onto this entity
2518 RSurf_ActiveWorldEntity();
2519 r_shadow_entitytolight = r_shadow_rtlight->matrix_worldtolight;
2520 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2521 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2522 VectorCopy(r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2523 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2524 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2526 r_refdef.worldmodel->DrawLight(r_refdef.worldentity, numsurfaces, surfacelist, trispvs);
2529 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2531 model_t *model = ent->model;
2532 if (!model->DrawLight)
2535 R_Shadow_SetupEntityLight(ent);
2537 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist, NULL);
2540 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2544 int numleafs, numsurfaces;
2545 int *leaflist, *surfacelist;
2546 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
2547 int numlightentities;
2548 int numshadowentities;
2549 entity_render_t *lightentities[MAX_EDICTS];
2550 entity_render_t *shadowentities[MAX_EDICTS];
2552 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2553 // skip lights that are basically invisible (color 0 0 0)
2554 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2557 // loading is done before visibility checks because loading should happen
2558 // all at once at the start of a level, not when it stalls gameplay.
2559 // (especially important to benchmarks)
2561 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2562 R_RTLight_Compile(rtlight);
2564 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2566 // look up the light style value at this time
2567 f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2568 VectorScale(rtlight->color, f, rtlight->currentcolor);
2570 if (rtlight->selected)
2572 f = 2 + sin(realtime * M_PI * 4.0);
2573 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2577 // if lightstyle is currently off, don't draw the light
2578 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2581 // if the light box is offscreen, skip it
2582 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2585 VectorCopy(rtlight->cullmins, r_shadow_rtlight_cullmins);
2586 VectorCopy(rtlight->cullmaxs, r_shadow_rtlight_cullmaxs);
2588 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2590 // compiled light, world available and can receive realtime lighting
2591 // retrieve leaf information
2592 numleafs = rtlight->static_numleafs;
2593 leaflist = rtlight->static_leaflist;
2594 leafpvs = rtlight->static_leafpvs;
2595 numsurfaces = rtlight->static_numsurfaces;
2596 surfacelist = rtlight->static_surfacelist;
2597 shadowtrispvs = rtlight->static_shadowtrispvs;
2598 lighttrispvs = rtlight->static_lighttrispvs;
2600 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2602 // dynamic light, world available and can receive realtime lighting
2603 // calculate lit surfaces and leafs
2604 R_Shadow_EnlargeLeafSurfaceTrisBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces, r_refdef.worldmodel->brush.shadowmesh ? r_refdef.worldmodel->brush.shadowmesh->numtriangles : r_refdef.worldmodel->surfmesh.num_triangles, r_refdef.worldmodel->surfmesh.num_triangles);
2605 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, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs);
2606 leaflist = r_shadow_buffer_leaflist;
2607 leafpvs = r_shadow_buffer_leafpvs;
2608 surfacelist = r_shadow_buffer_surfacelist;
2609 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
2610 lighttrispvs = r_shadow_buffer_lighttrispvs;
2611 // if the reduced leaf bounds are offscreen, skip it
2612 if (R_CullBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2623 shadowtrispvs = NULL;
2624 lighttrispvs = NULL;
2626 // check if light is illuminating any visible leafs
2629 for (i = 0;i < numleafs;i++)
2630 if (r_viewcache.world_leafvisible[leaflist[i]])
2635 // set up a scissor rectangle for this light
2636 if (R_Shadow_ScissorForBBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2639 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
2641 // make a list of lit entities and shadow casting entities
2642 numlightentities = 0;
2643 numshadowentities = 0;
2644 // add dynamic entities that are lit by the light
2645 if (r_drawentities.integer)
2647 for (i = 0;i < r_refdef.numentities;i++)
2650 entity_render_t *ent = r_refdef.entities[i];
2652 if (!BoxesOverlap(ent->mins, ent->maxs, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2654 // skip the object entirely if it is not within the valid
2655 // shadow-casting region (which includes the lit region)
2656 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, r_shadow_rtlight_numfrustumplanes, r_shadow_rtlight_frustumplanes))
2658 if (!(model = ent->model))
2660 if (r_viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
2662 // this entity wants to receive light, is visible, and is
2663 // inside the light box
2664 // TODO: check if the surfaces in the model can receive light
2665 // so now check if it's in a leaf seen by the light
2666 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2668 lightentities[numlightentities++] = ent;
2669 // since it is lit, it probably also casts a shadow...
2670 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2671 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2672 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2673 shadowentities[numshadowentities++] = ent;
2675 else if (ent->flags & RENDER_SHADOW)
2677 // this entity is not receiving light, but may still need to
2679 // TODO: check if the surfaces in the model can cast shadow
2680 // now check if it is in a leaf seen by the light
2681 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2683 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2684 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2685 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2686 shadowentities[numshadowentities++] = ent;
2691 // return if there's nothing at all to light
2692 if (!numlightentities && !numsurfaces)
2695 // don't let sound skip if going slow
2696 if (r_refdef.extraupdate)
2699 // make this the active rtlight for rendering purposes
2700 R_Shadow_RenderMode_ActiveLight(rtlight);
2701 // count this light in the r_speeds
2702 r_refdef.stats.lights++;
2705 if (numsurfaces + numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2707 // draw stencil shadow volumes to mask off pixels that are in shadow
2708 // so that they won't receive lighting
2712 R_Shadow_RenderMode_StencilShadowVolumes();
2714 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
2715 for (i = 0;i < numshadowentities;i++)
2716 R_Shadow_DrawEntityShadow(shadowentities[i]);
2719 // optionally draw visible shape of the shadow volumes
2720 // for performance analysis by level designers
2721 if (r_showshadowvolumes.integer)
2723 R_Shadow_RenderMode_VisibleShadowVolumes();
2725 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
2726 for (i = 0;i < numshadowentities;i++)
2727 R_Shadow_DrawEntityShadow(shadowentities[i]);
2731 if (numsurfaces + numlightentities)
2733 // draw lighting in the unmasked areas
2734 R_Shadow_RenderMode_Lighting(usestencil, false);
2736 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
2737 for (i = 0;i < numlightentities;i++)
2738 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2740 // optionally draw the illuminated areas
2741 // for performance analysis by level designers
2742 if (r_showlighting.integer)
2744 R_Shadow_RenderMode_VisibleLighting(usestencil && !r_showdisabledepthtest.integer, false);
2746 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
2747 for (i = 0;i < numlightentities;i++)
2748 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2753 void R_Shadow_DrawLightSprites(void);
2754 void R_ShadowVolumeLighting(qboolean visible)
2759 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2760 R_Shadow_EditLights_Reload_f();
2762 if (r_editlights.integer)
2763 R_Shadow_DrawLightSprites();
2765 R_Shadow_RenderMode_Begin();
2767 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2768 if (r_shadow_debuglight.integer >= 0)
2770 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2771 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2772 R_DrawRTLight(&light->rtlight, visible);
2775 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2776 if (light->flags & flag)
2777 R_DrawRTLight(&light->rtlight, visible);
2778 if (r_refdef.rtdlight)
2779 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
2780 R_DrawRTLight(&r_refdef.lights[lnum], visible);
2782 R_Shadow_RenderMode_End();
2785 extern void R_SetupView(const matrix4x4_t *matrix);
2786 extern cvar_t r_shadows_throwdistance;
2787 void R_DrawModelShadows(void)
2790 float relativethrowdistance;
2791 entity_render_t *ent;
2792 vec3_t relativelightorigin;
2793 vec3_t relativelightdirection;
2794 vec3_t relativeshadowmins, relativeshadowmaxs;
2797 if (!r_drawentities.integer || !gl_stencil)
2801 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2803 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2805 if (gl_ext_separatestencil.integer)
2806 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
2807 else if (gl_ext_stenciltwoside.integer)
2808 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
2810 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
2812 R_Shadow_RenderMode_StencilShadowVolumes();
2814 for (i = 0;i < r_refdef.numentities;i++)
2816 ent = r_refdef.entities[i];
2817 // cast shadows from anything that is not a submodel of the map
2818 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
2820 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
2821 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
2822 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
2823 VectorNegate(ent->modellight_lightdir, relativelightdirection);
2824 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
2825 RSurf_ActiveModelEntity(ent, false, false);
2826 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2830 // not really the right mode, but this will disable any silly stencil features
2831 R_Shadow_RenderMode_VisibleLighting(true, true);
2833 // vertex coordinates for a quad that covers the screen exactly
2834 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
2835 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
2836 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
2837 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
2839 // set up ortho view for rendering this pass
2840 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
2841 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2842 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2843 GL_ScissorTest(true);
2844 R_Mesh_Matrix(&identitymatrix);
2845 R_Mesh_ResetTextureState();
2846 R_Mesh_VertexPointer(vertex3f);
2847 R_Mesh_ColorPointer(NULL);
2849 // set up a 50% darkening blend on shadowed areas
2850 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2851 GL_DepthTest(false);
2852 GL_DepthMask(false);
2853 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2854 GL_Color(0, 0, 0, 0.5);
2855 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2856 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
2857 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2858 qglStencilMask(~0);CHECKGLERROR
2859 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
2860 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
2862 // apply the blend to the shadowed areas
2863 R_Mesh_Draw(0, 4, 2, polygonelements);
2865 // restoring the perspective view is done by R_RenderScene
2866 //R_SetupView(&r_view.matrix);
2868 // restore other state to normal
2869 R_Shadow_RenderMode_End();
2873 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2874 typedef struct suffixinfo_s
2877 qboolean flipx, flipy, flipdiagonal;
2880 static suffixinfo_t suffix[3][6] =
2883 {"px", false, false, false},
2884 {"nx", false, false, false},
2885 {"py", false, false, false},
2886 {"ny", false, false, false},
2887 {"pz", false, false, false},
2888 {"nz", false, false, false}
2891 {"posx", false, false, false},
2892 {"negx", false, false, false},
2893 {"posy", false, false, false},
2894 {"negy", false, false, false},
2895 {"posz", false, false, false},
2896 {"negz", false, false, false}
2899 {"rt", true, false, true},
2900 {"lf", false, true, true},
2901 {"ft", true, true, false},
2902 {"bk", false, false, false},
2903 {"up", true, false, true},
2904 {"dn", true, false, true}
2908 static int componentorder[4] = {0, 1, 2, 3};
2910 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2912 int i, j, cubemapsize;
2913 unsigned char *cubemappixels, *image_rgba;
2914 rtexture_t *cubemaptexture;
2916 // must start 0 so the first loadimagepixels has no requested width/height
2918 cubemappixels = NULL;
2919 cubemaptexture = NULL;
2920 // keep trying different suffix groups (posx, px, rt) until one loads
2921 for (j = 0;j < 3 && !cubemappixels;j++)
2923 // load the 6 images in the suffix group
2924 for (i = 0;i < 6;i++)
2926 // generate an image name based on the base and and suffix
2927 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2929 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2931 // an image loaded, make sure width and height are equal
2932 if (image_width == image_height)
2934 // if this is the first image to load successfully, allocate the cubemap memory
2935 if (!cubemappixels && image_width >= 1)
2937 cubemapsize = image_width;
2938 // note this clears to black, so unavailable sides are black
2939 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2941 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2943 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);
2946 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2948 Mem_Free(image_rgba);
2952 // if a cubemap loaded, upload it
2955 if (!r_shadow_filters_texturepool)
2956 r_shadow_filters_texturepool = R_AllocTexturePool();
2957 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2958 Mem_Free(cubemappixels);
2962 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2963 for (j = 0;j < 3;j++)
2964 for (i = 0;i < 6;i++)
2965 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2966 Con_Print(" and was unable to find any of them.\n");
2968 return cubemaptexture;
2971 rtexture_t *R_Shadow_Cubemap(const char *basename)
2974 for (i = 0;i < numcubemaps;i++)
2975 if (!strcasecmp(cubemaps[i].basename, basename))
2976 return cubemaps[i].texture;
2977 if (i >= MAX_CUBEMAPS)
2978 return r_texture_whitecube;
2980 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
2981 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2982 if (!cubemaps[i].texture)
2983 cubemaps[i].texture = r_texture_whitecube;
2984 return cubemaps[i].texture;
2987 void R_Shadow_FreeCubemaps(void)
2990 R_FreeTexturePool(&r_shadow_filters_texturepool);
2993 dlight_t *R_Shadow_NewWorldLight(void)
2996 light = (dlight_t *)Mem_Alloc(r_main_mempool, sizeof(dlight_t));
2997 light->next = r_shadow_worldlightchain;
2998 r_shadow_worldlightchain = light;
3002 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)
3005 // validate parameters
3006 if (style < 0 || style >= MAX_LIGHTSTYLES)
3008 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3014 // copy to light properties
3015 VectorCopy(origin, light->origin);
3016 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3017 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3018 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3019 light->color[0] = max(color[0], 0);
3020 light->color[1] = max(color[1], 0);
3021 light->color[2] = max(color[2], 0);
3022 light->radius = max(radius, 0);
3023 light->style = style;
3024 light->shadow = shadowenable;
3025 light->corona = corona;
3026 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3027 light->coronasizescale = coronasizescale;
3028 light->ambientscale = ambientscale;
3029 light->diffusescale = diffusescale;
3030 light->specularscale = specularscale;
3031 light->flags = flags;
3033 // update renderable light data
3034 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
3035 R_RTLight_Update(&light->rtlight, true, &matrix, light->color, light->style, light->cubemapname[0] ? light->cubemapname : NULL, light->shadow, light->corona, light->coronasizescale, light->ambientscale, light->diffusescale, light->specularscale, light->flags);
3038 void R_Shadow_FreeWorldLight(dlight_t *light)
3040 dlight_t **lightpointer;
3041 R_RTLight_Uncompile(&light->rtlight);
3042 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3043 if (*lightpointer != light)
3044 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
3045 *lightpointer = light->next;
3049 void R_Shadow_ClearWorldLights(void)
3051 while (r_shadow_worldlightchain)
3052 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3053 r_shadow_selectedlight = NULL;
3054 R_Shadow_FreeCubemaps();
3057 void R_Shadow_SelectLight(dlight_t *light)
3059 if (r_shadow_selectedlight)
3060 r_shadow_selectedlight->selected = false;
3061 r_shadow_selectedlight = light;
3062 if (r_shadow_selectedlight)
3063 r_shadow_selectedlight->selected = true;
3066 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3068 // this is never batched (there can be only one)
3069 float scale = r_editlights_cursorgrid.value * 0.5f;
3070 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);
3073 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3075 // this is never batched (due to the ent parameter changing every time)
3076 // so numsurfaces == 1 and surfacelist[0] == lightnumber
3078 const dlight_t *light = (dlight_t *)ent;
3080 if (light->selected)
3081 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3084 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);
3087 void R_Shadow_DrawLightSprites(void)
3092 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3093 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 1+(i % 5), &light->rtlight);
3094 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
3097 void R_Shadow_SelectLightInView(void)
3099 float bestrating, rating, temp[3];
3100 dlight_t *best, *light;
3103 for (light = r_shadow_worldlightchain;light;light = light->next)
3105 VectorSubtract(light->origin, r_view.origin, temp);
3106 rating = (DotProduct(temp, r_view.forward) / sqrt(DotProduct(temp, temp)));
3109 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3110 if (bestrating < rating && CL_Move(light->origin, vec3_origin, vec3_origin, r_view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
3112 bestrating = rating;
3117 R_Shadow_SelectLight(best);
3120 void R_Shadow_LoadWorldLights(void)
3122 int n, a, style, shadow, flags;
3123 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3124 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3125 if (r_refdef.worldmodel == NULL)
3127 Con_Print("No map loaded.\n");
3130 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3131 strlcat (name, ".rtlights", sizeof (name));
3132 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3142 for (;COM_Parse(t, true) && strcmp(
3143 if (COM_Parse(t, true))
3145 if (com_token[0] == '!')
3148 origin[0] = atof(com_token+1);
3151 origin[0] = atof(com_token);
3156 while (*s && *s != '\n' && *s != '\r')
3162 // check for modifier flags
3169 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);
3172 flags = LIGHTFLAG_REALTIMEMODE;
3180 coronasizescale = 0.25f;
3182 VectorClear(angles);
3185 if (a < 9 || !strcmp(cubemapname, "\"\""))
3187 // remove quotes on cubemapname
3188 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3191 namelen = strlen(cubemapname) - 2;
3192 memmove(cubemapname, cubemapname + 1, namelen);
3193 cubemapname[namelen] = '\0';
3197 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);
3200 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3208 Con_Printf("invalid rtlights file \"%s\"\n", name);
3209 Mem_Free(lightsstring);
3213 void R_Shadow_SaveWorldLights(void)
3216 size_t bufchars, bufmaxchars;
3218 char name[MAX_QPATH];
3219 char line[MAX_INPUTLINE];
3220 if (!r_shadow_worldlightchain)
3222 if (r_refdef.worldmodel == NULL)
3224 Con_Print("No map loaded.\n");
3227 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3228 strlcat (name, ".rtlights", sizeof (name));
3229 bufchars = bufmaxchars = 0;
3231 for (light = r_shadow_worldlightchain;light;light = light->next)
3233 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3234 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);
3235 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3236 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]);
3238 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);
3239 if (bufchars + strlen(line) > bufmaxchars)
3241 bufmaxchars = bufchars + strlen(line) + 2048;
3243 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3247 memcpy(buf, oldbuf, bufchars);
3253 memcpy(buf + bufchars, line, strlen(line));
3254 bufchars += strlen(line);
3258 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3263 void R_Shadow_LoadLightsFile(void)
3266 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3267 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3268 if (r_refdef.worldmodel == NULL)
3270 Con_Print("No map loaded.\n");
3273 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3274 strlcat (name, ".lights", sizeof (name));
3275 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3283 while (*s && *s != '\n' && *s != '\r')
3289 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);
3293 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);
3296 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3297 radius = bound(15, radius, 4096);
3298 VectorScale(color, (2.0f / (8388608.0f)), color);
3299 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3307 Con_Printf("invalid lights file \"%s\"\n", name);
3308 Mem_Free(lightsstring);
3312 // tyrlite/hmap2 light types in the delay field
3313 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3315 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3317 int entnum, style, islight, skin, pflags, effects, type, n;
3320 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3321 char key[256], value[MAX_INPUTLINE];
3323 if (r_refdef.worldmodel == NULL)
3325 Con_Print("No map loaded.\n");
3328 // try to load a .ent file first
3329 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3330 strlcat (key, ".ent", sizeof (key));
3331 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3332 // and if that is not found, fall back to the bsp file entity string
3334 data = r_refdef.worldmodel->brush.entities;
3337 for (entnum = 0;COM_ParseTokenConsole(&data) && com_token[0] == '{';entnum++)
3339 type = LIGHTTYPE_MINUSX;
3340 origin[0] = origin[1] = origin[2] = 0;
3341 originhack[0] = originhack[1] = originhack[2] = 0;
3342 angles[0] = angles[1] = angles[2] = 0;
3343 color[0] = color[1] = color[2] = 1;
3344 light[0] = light[1] = light[2] = 1;light[3] = 300;
3345 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3355 if (!COM_ParseTokenConsole(&data))
3357 if (com_token[0] == '}')
3358 break; // end of entity
3359 if (com_token[0] == '_')
3360 strlcpy(key, com_token + 1, sizeof(key));
3362 strlcpy(key, com_token, sizeof(key));
3363 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3364 key[strlen(key)-1] = 0;
3365 if (!COM_ParseTokenConsole(&data))
3367 strlcpy(value, com_token, sizeof(value));
3369 // now that we have the key pair worked out...
3370 if (!strcmp("light", key))
3372 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3376 light[0] = vec[0] * (1.0f / 256.0f);
3377 light[1] = vec[0] * (1.0f / 256.0f);
3378 light[2] = vec[0] * (1.0f / 256.0f);
3384 light[0] = vec[0] * (1.0f / 255.0f);
3385 light[1] = vec[1] * (1.0f / 255.0f);
3386 light[2] = vec[2] * (1.0f / 255.0f);
3390 else if (!strcmp("delay", key))
3392 else if (!strcmp("origin", key))
3393 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3394 else if (!strcmp("angle", key))
3395 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3396 else if (!strcmp("angles", key))
3397 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3398 else if (!strcmp("color", key))
3399 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3400 else if (!strcmp("wait", key))
3401 fadescale = atof(value);
3402 else if (!strcmp("classname", key))
3404 if (!strncmp(value, "light", 5))
3407 if (!strcmp(value, "light_fluoro"))
3412 overridecolor[0] = 1;
3413 overridecolor[1] = 1;
3414 overridecolor[2] = 1;
3416 if (!strcmp(value, "light_fluorospark"))
3421 overridecolor[0] = 1;
3422 overridecolor[1] = 1;
3423 overridecolor[2] = 1;
3425 if (!strcmp(value, "light_globe"))
3430 overridecolor[0] = 1;
3431 overridecolor[1] = 0.8;
3432 overridecolor[2] = 0.4;
3434 if (!strcmp(value, "light_flame_large_yellow"))
3439 overridecolor[0] = 1;
3440 overridecolor[1] = 0.5;
3441 overridecolor[2] = 0.1;
3443 if (!strcmp(value, "light_flame_small_yellow"))
3448 overridecolor[0] = 1;
3449 overridecolor[1] = 0.5;
3450 overridecolor[2] = 0.1;
3452 if (!strcmp(value, "light_torch_small_white"))
3457 overridecolor[0] = 1;
3458 overridecolor[1] = 0.5;
3459 overridecolor[2] = 0.1;
3461 if (!strcmp(value, "light_torch_small_walltorch"))
3466 overridecolor[0] = 1;
3467 overridecolor[1] = 0.5;
3468 overridecolor[2] = 0.1;
3472 else if (!strcmp("style", key))
3473 style = atoi(value);
3474 else if (!strcmp("skin", key))
3475 skin = (int)atof(value);
3476 else if (!strcmp("pflags", key))
3477 pflags = (int)atof(value);
3478 else if (!strcmp("effects", key))
3479 effects = (int)atof(value);
3480 else if (r_refdef.worldmodel->type == mod_brushq3)
3482 if (!strcmp("scale", key))
3483 lightscale = atof(value);
3484 if (!strcmp("fade", key))
3485 fadescale = atof(value);
3490 if (lightscale <= 0)
3494 if (color[0] == color[1] && color[0] == color[2])
3496 color[0] *= overridecolor[0];
3497 color[1] *= overridecolor[1];
3498 color[2] *= overridecolor[2];
3500 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3501 color[0] = color[0] * light[0];
3502 color[1] = color[1] * light[1];
3503 color[2] = color[2] * light[2];
3506 case LIGHTTYPE_MINUSX:
3508 case LIGHTTYPE_RECIPX:
3510 VectorScale(color, (1.0f / 16.0f), color);
3512 case LIGHTTYPE_RECIPXX:
3514 VectorScale(color, (1.0f / 16.0f), color);
3517 case LIGHTTYPE_NONE:
3521 case LIGHTTYPE_MINUSXX:
3524 VectorAdd(origin, originhack, origin);
3526 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);
3529 Mem_Free(entfiledata);
3533 void R_Shadow_SetCursorLocationForView(void)
3536 vec3_t dest, endpos;
3538 VectorMA(r_view.origin, r_editlights_cursordistance.value, r_view.forward, dest);
3539 trace = CL_Move(r_view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
3540 if (trace.fraction < 1)
3542 dist = trace.fraction * r_editlights_cursordistance.value;
3543 push = r_editlights_cursorpushback.value;
3547 VectorMA(trace.endpos, push, r_view.forward, endpos);
3548 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3552 VectorClear( endpos );
3554 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3555 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3556 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3559 void R_Shadow_UpdateWorldLightSelection(void)
3561 if (r_editlights.integer)
3563 R_Shadow_SetCursorLocationForView();
3564 R_Shadow_SelectLightInView();
3567 R_Shadow_SelectLight(NULL);
3570 void R_Shadow_EditLights_Clear_f(void)
3572 R_Shadow_ClearWorldLights();
3575 void R_Shadow_EditLights_Reload_f(void)
3577 if (!r_refdef.worldmodel)
3579 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3580 R_Shadow_ClearWorldLights();
3581 R_Shadow_LoadWorldLights();
3582 if (r_shadow_worldlightchain == NULL)
3584 R_Shadow_LoadLightsFile();
3585 if (r_shadow_worldlightchain == NULL)
3586 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3590 void R_Shadow_EditLights_Save_f(void)
3592 if (!r_refdef.worldmodel)
3594 R_Shadow_SaveWorldLights();
3597 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3599 R_Shadow_ClearWorldLights();
3600 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3603 void R_Shadow_EditLights_ImportLightsFile_f(void)
3605 R_Shadow_ClearWorldLights();
3606 R_Shadow_LoadLightsFile();
3609 void R_Shadow_EditLights_Spawn_f(void)
3612 if (!r_editlights.integer)
3614 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3617 if (Cmd_Argc() != 1)
3619 Con_Print("r_editlights_spawn does not take parameters\n");
3622 color[0] = color[1] = color[2] = 1;
3623 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3626 void R_Shadow_EditLights_Edit_f(void)
3628 vec3_t origin, angles, color;
3629 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3630 int style, shadows, flags, normalmode, realtimemode;
3631 char cubemapname[MAX_INPUTLINE];
3632 if (!r_editlights.integer)
3634 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3637 if (!r_shadow_selectedlight)
3639 Con_Print("No selected light.\n");
3642 VectorCopy(r_shadow_selectedlight->origin, origin);
3643 VectorCopy(r_shadow_selectedlight->angles, angles);
3644 VectorCopy(r_shadow_selectedlight->color, color);
3645 radius = r_shadow_selectedlight->radius;
3646 style = r_shadow_selectedlight->style;
3647 if (r_shadow_selectedlight->cubemapname)
3648 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3651 shadows = r_shadow_selectedlight->shadow;
3652 corona = r_shadow_selectedlight->corona;
3653 coronasizescale = r_shadow_selectedlight->coronasizescale;
3654 ambientscale = r_shadow_selectedlight->ambientscale;
3655 diffusescale = r_shadow_selectedlight->diffusescale;
3656 specularscale = r_shadow_selectedlight->specularscale;
3657 flags = r_shadow_selectedlight->flags;
3658 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3659 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3660 if (!strcmp(Cmd_Argv(1), "origin"))
3662 if (Cmd_Argc() != 5)
3664 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3667 origin[0] = atof(Cmd_Argv(2));
3668 origin[1] = atof(Cmd_Argv(3));
3669 origin[2] = atof(Cmd_Argv(4));
3671 else if (!strcmp(Cmd_Argv(1), "originx"))
3673 if (Cmd_Argc() != 3)
3675 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3678 origin[0] = atof(Cmd_Argv(2));
3680 else if (!strcmp(Cmd_Argv(1), "originy"))
3682 if (Cmd_Argc() != 3)
3684 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3687 origin[1] = atof(Cmd_Argv(2));
3689 else if (!strcmp(Cmd_Argv(1), "originz"))
3691 if (Cmd_Argc() != 3)
3693 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3696 origin[2] = atof(Cmd_Argv(2));
3698 else if (!strcmp(Cmd_Argv(1), "move"))
3700 if (Cmd_Argc() != 5)
3702 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3705 origin[0] += atof(Cmd_Argv(2));
3706 origin[1] += atof(Cmd_Argv(3));
3707 origin[2] += atof(Cmd_Argv(4));
3709 else if (!strcmp(Cmd_Argv(1), "movex"))
3711 if (Cmd_Argc() != 3)
3713 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3716 origin[0] += atof(Cmd_Argv(2));
3718 else if (!strcmp(Cmd_Argv(1), "movey"))
3720 if (Cmd_Argc() != 3)
3722 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3725 origin[1] += atof(Cmd_Argv(2));
3727 else if (!strcmp(Cmd_Argv(1), "movez"))
3729 if (Cmd_Argc() != 3)
3731 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3734 origin[2] += atof(Cmd_Argv(2));
3736 else if (!strcmp(Cmd_Argv(1), "angles"))
3738 if (Cmd_Argc() != 5)
3740 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3743 angles[0] = atof(Cmd_Argv(2));
3744 angles[1] = atof(Cmd_Argv(3));
3745 angles[2] = atof(Cmd_Argv(4));
3747 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3749 if (Cmd_Argc() != 3)
3751 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3754 angles[0] = atof(Cmd_Argv(2));
3756 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3758 if (Cmd_Argc() != 3)
3760 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3763 angles[1] = atof(Cmd_Argv(2));
3765 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3767 if (Cmd_Argc() != 3)
3769 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3772 angles[2] = atof(Cmd_Argv(2));
3774 else if (!strcmp(Cmd_Argv(1), "color"))
3776 if (Cmd_Argc() != 5)
3778 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3781 color[0] = atof(Cmd_Argv(2));
3782 color[1] = atof(Cmd_Argv(3));
3783 color[2] = atof(Cmd_Argv(4));
3785 else if (!strcmp(Cmd_Argv(1), "radius"))
3787 if (Cmd_Argc() != 3)
3789 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3792 radius = atof(Cmd_Argv(2));
3794 else if (!strcmp(Cmd_Argv(1), "colorscale"))
3796 if (Cmd_Argc() == 3)
3798 double scale = atof(Cmd_Argv(2));
3805 if (Cmd_Argc() != 5)
3807 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
3810 color[0] *= atof(Cmd_Argv(2));
3811 color[1] *= atof(Cmd_Argv(3));
3812 color[2] *= atof(Cmd_Argv(4));
3815 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
3817 if (Cmd_Argc() != 3)
3819 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3822 radius *= atof(Cmd_Argv(2));
3824 else if (!strcmp(Cmd_Argv(1), "style"))
3826 if (Cmd_Argc() != 3)
3828 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3831 style = atoi(Cmd_Argv(2));
3833 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3837 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3840 if (Cmd_Argc() == 3)
3841 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
3845 else if (!strcmp(Cmd_Argv(1), "shadows"))
3847 if (Cmd_Argc() != 3)
3849 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3852 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3854 else if (!strcmp(Cmd_Argv(1), "corona"))
3856 if (Cmd_Argc() != 3)
3858 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3861 corona = atof(Cmd_Argv(2));
3863 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3865 if (Cmd_Argc() != 3)
3867 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3870 coronasizescale = atof(Cmd_Argv(2));
3872 else if (!strcmp(Cmd_Argv(1), "ambient"))
3874 if (Cmd_Argc() != 3)
3876 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3879 ambientscale = atof(Cmd_Argv(2));
3881 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3883 if (Cmd_Argc() != 3)
3885 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3888 diffusescale = atof(Cmd_Argv(2));
3890 else if (!strcmp(Cmd_Argv(1), "specular"))
3892 if (Cmd_Argc() != 3)
3894 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3897 specularscale = atof(Cmd_Argv(2));
3899 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3901 if (Cmd_Argc() != 3)
3903 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3906 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3908 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3910 if (Cmd_Argc() != 3)
3912 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3915 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3919 Con_Print("usage: r_editlights_edit [property] [value]\n");
3920 Con_Print("Selected light's properties:\n");
3921 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3922 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3923 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3924 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3925 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3926 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3927 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3928 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3929 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3930 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3931 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3932 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3933 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3934 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3937 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3938 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3941 void R_Shadow_EditLights_EditAll_f(void)
3945 if (!r_editlights.integer)
3947 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3951 for (light = r_shadow_worldlightchain;light;light = light->next)
3953 R_Shadow_SelectLight(light);
3954 R_Shadow_EditLights_Edit_f();
3958 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3960 int lightnumber, lightcount;
3964 if (!r_editlights.integer)
3970 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3971 if (light == r_shadow_selectedlight)
3972 lightnumber = lightcount;
3973 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;
3974 if (r_shadow_selectedlight == NULL)
3976 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3977 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;
3978 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;
3979 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;
3980 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3981 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3982 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3983 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;
3984 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3985 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3986 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3987 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3988 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3989 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;
3990 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;
3993 void R_Shadow_EditLights_ToggleShadow_f(void)
3995 if (!r_editlights.integer)
3997 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4000 if (!r_shadow_selectedlight)
4002 Con_Print("No selected light.\n");
4005 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);
4008 void R_Shadow_EditLights_ToggleCorona_f(void)
4010 if (!r_editlights.integer)
4012 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4015 if (!r_shadow_selectedlight)
4017 Con_Print("No selected light.\n");
4020 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);
4023 void R_Shadow_EditLights_Remove_f(void)
4025 if (!r_editlights.integer)
4027 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4030 if (!r_shadow_selectedlight)
4032 Con_Print("No selected light.\n");
4035 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4036 r_shadow_selectedlight = NULL;
4039 void R_Shadow_EditLights_Help_f(void)
4042 "Documentation on r_editlights system:\n"
4044 "r_editlights : enable/disable editing mode\n"
4045 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4046 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4047 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4048 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4049 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4051 "r_editlights_help : this help\n"
4052 "r_editlights_clear : remove all lights\n"
4053 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4054 "r_editlights_save : save to .rtlights file\n"
4055 "r_editlights_spawn : create a light with default settings\n"
4056 "r_editlights_edit command : edit selected light - more documentation below\n"
4057 "r_editlights_remove : remove selected light\n"
4058 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4059 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4060 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4062 "origin x y z : set light location\n"
4063 "originx x: set x component of light location\n"
4064 "originy y: set y component of light location\n"
4065 "originz z: set z component of light location\n"
4066 "move x y z : adjust light location\n"
4067 "movex x: adjust x component of light location\n"
4068 "movey y: adjust y component of light location\n"
4069 "movez z: adjust z component of light location\n"
4070 "angles x y z : set light angles\n"
4071 "anglesx x: set x component of light angles\n"
4072 "anglesy y: set y component of light angles\n"
4073 "anglesz z: set z component of light angles\n"
4074 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4075 "radius radius : set radius (size) of light\n"
4076 "colorscale grey : multiply color of light (1 does nothing)\n"
4077 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4078 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4079 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4080 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4081 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4082 "shadows 1/0 : turn on/off shadows\n"
4083 "corona n : set corona intensity\n"
4084 "coronasize n : set corona size (0-1)\n"
4085 "ambient n : set ambient intensity (0-1)\n"
4086 "diffuse n : set diffuse intensity (0-1)\n"
4087 "specular n : set specular intensity (0-1)\n"
4088 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4089 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4090 "<nothing> : print light properties to console\n"
4094 void R_Shadow_EditLights_CopyInfo_f(void)
4096 if (!r_editlights.integer)
4098 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4101 if (!r_shadow_selectedlight)
4103 Con_Print("No selected light.\n");
4106 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4107 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4108 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4109 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4110 if (r_shadow_selectedlight->cubemapname)
4111 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
4113 r_shadow_bufferlight.cubemapname[0] = 0;
4114 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4115 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4116 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4117 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4118 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4119 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4120 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4123 void R_Shadow_EditLights_PasteInfo_f(void)
4125 if (!r_editlights.integer)
4127 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4130 if (!r_shadow_selectedlight)
4132 Con_Print("No selected light.\n");
4135 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);
4138 void R_Shadow_EditLights_Init(void)
4140 Cvar_RegisterVariable(&r_editlights);
4141 Cvar_RegisterVariable(&r_editlights_cursordistance);
4142 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4143 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4144 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4145 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4146 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
4147 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
4148 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)");
4149 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
4150 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
4151 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
4152 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)");
4153 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
4154 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
4155 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
4156 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
4157 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
4158 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
4159 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)");