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_attenuationgradienttexture;
202 rtexture_t *r_shadow_attenuation2dtexture;
203 rtexture_t *r_shadow_attenuation3dtexture;
205 // lights are reloaded when this changes
206 char r_shadow_mapname[MAX_QPATH];
208 // used only for light filters (cubemaps)
209 rtexturepool_t *r_shadow_filters_texturepool;
211 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"};
212 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"};
213 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
214 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
215 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)"};
216 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"};
217 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
218 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
219 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
220 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
221 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
222 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
223 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
224 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
225 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)"};
226 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
227 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
228 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
229 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
230 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)"};
231 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"};
232 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"};
233 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
234 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
235 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"};
236 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
237 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
238 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)"};
239 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
240 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
241 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)"};
242 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)"};
243 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
244 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
245 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
246 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
247 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
248 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
249 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
250 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
252 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
253 #define ATTENTABLESIZE 256
254 // 1D gradient, 2D circle and 3D sphere attenuation textures
255 #define ATTEN1DSIZE 32
256 #define ATTEN2DSIZE 64
257 #define ATTEN3DSIZE 32
259 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
260 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
261 static float r_shadow_attentable[ATTENTABLESIZE+1];
263 rtlight_t *r_shadow_compilingrtlight;
264 dlight_t *r_shadow_worldlightchain;
265 dlight_t *r_shadow_selectedlight;
266 dlight_t r_shadow_bufferlight;
267 vec3_t r_editlights_cursorlocation;
269 extern int con_vislines;
271 typedef struct cubemapinfo_s
278 #define MAX_CUBEMAPS 256
279 static int numcubemaps;
280 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
282 void R_Shadow_UncompileWorldLights(void);
283 void R_Shadow_ClearWorldLights(void);
284 void R_Shadow_SaveWorldLights(void);
285 void R_Shadow_LoadWorldLights(void);
286 void R_Shadow_LoadLightsFile(void);
287 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
288 void R_Shadow_EditLights_Reload_f(void);
289 void R_Shadow_ValidateCvars(void);
290 static void R_Shadow_MakeTextures(void);
292 void r_shadow_start(void)
294 // allocate vertex processing arrays
296 r_shadow_attenuationgradienttexture = NULL;
297 r_shadow_attenuation2dtexture = NULL;
298 r_shadow_attenuation3dtexture = NULL;
299 r_shadow_texturepool = NULL;
300 r_shadow_filters_texturepool = NULL;
301 R_Shadow_ValidateCvars();
302 R_Shadow_MakeTextures();
303 maxshadowtriangles = 0;
304 shadowelements = NULL;
305 maxshadowvertices = 0;
306 shadowvertex3f = NULL;
314 shadowmarklist = NULL;
316 r_shadow_buffer_numleafpvsbytes = 0;
317 r_shadow_buffer_leafpvs = NULL;
318 r_shadow_buffer_leaflist = NULL;
319 r_shadow_buffer_numsurfacepvsbytes = 0;
320 r_shadow_buffer_surfacepvs = NULL;
321 r_shadow_buffer_surfacelist = NULL;
322 r_shadow_buffer_numshadowtrispvsbytes = 0;
323 r_shadow_buffer_shadowtrispvs = NULL;
324 r_shadow_buffer_numlighttrispvsbytes = 0;
325 r_shadow_buffer_lighttrispvs = NULL;
328 void r_shadow_shutdown(void)
330 R_Shadow_UncompileWorldLights();
332 r_shadow_attenuationgradienttexture = NULL;
333 r_shadow_attenuation2dtexture = NULL;
334 r_shadow_attenuation3dtexture = NULL;
335 R_FreeTexturePool(&r_shadow_texturepool);
336 R_FreeTexturePool(&r_shadow_filters_texturepool);
337 maxshadowtriangles = 0;
339 Mem_Free(shadowelements);
340 shadowelements = NULL;
342 Mem_Free(shadowvertex3f);
343 shadowvertex3f = NULL;
346 Mem_Free(vertexupdate);
349 Mem_Free(vertexremap);
355 Mem_Free(shadowmark);
358 Mem_Free(shadowmarklist);
359 shadowmarklist = NULL;
361 r_shadow_buffer_numleafpvsbytes = 0;
362 if (r_shadow_buffer_leafpvs)
363 Mem_Free(r_shadow_buffer_leafpvs);
364 r_shadow_buffer_leafpvs = NULL;
365 if (r_shadow_buffer_leaflist)
366 Mem_Free(r_shadow_buffer_leaflist);
367 r_shadow_buffer_leaflist = NULL;
368 r_shadow_buffer_numsurfacepvsbytes = 0;
369 if (r_shadow_buffer_surfacepvs)
370 Mem_Free(r_shadow_buffer_surfacepvs);
371 r_shadow_buffer_surfacepvs = NULL;
372 if (r_shadow_buffer_surfacelist)
373 Mem_Free(r_shadow_buffer_surfacelist);
374 r_shadow_buffer_surfacelist = NULL;
375 r_shadow_buffer_numshadowtrispvsbytes = 0;
376 if (r_shadow_buffer_shadowtrispvs)
377 Mem_Free(r_shadow_buffer_shadowtrispvs);
378 r_shadow_buffer_numlighttrispvsbytes = 0;
379 if (r_shadow_buffer_lighttrispvs)
380 Mem_Free(r_shadow_buffer_lighttrispvs);
383 void r_shadow_newmap(void)
387 void R_Shadow_Help_f(void)
390 "Documentation on r_shadow system:\n"
392 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
393 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
394 "r_shadow_debuglight : render only this light number (-1 = all)\n"
395 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
396 "r_shadow_gloss2intensity : brightness of forced gloss\n"
397 "r_shadow_glossintensity : brightness of textured gloss\n"
398 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
399 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
400 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
401 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
402 "r_shadow_portallight : use portal visibility for static light precomputation\n"
403 "r_shadow_projectdistance : shadow volume projection distance\n"
404 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
405 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
406 "r_shadow_realtime_world : use high quality world lighting mode\n"
407 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
408 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
409 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
410 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
411 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
412 "r_shadow_scissor : use scissor optimization\n"
413 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
414 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
415 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
416 "r_showlighting : useful for performance testing; bright = slow!\n"
417 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
419 "r_shadow_help : this help\n"
423 void R_Shadow_Init(void)
425 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
426 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
427 Cvar_RegisterVariable(&r_shadow_usenormalmap);
428 Cvar_RegisterVariable(&r_shadow_debuglight);
429 Cvar_RegisterVariable(&r_shadow_gloss);
430 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
431 Cvar_RegisterVariable(&r_shadow_glossintensity);
432 Cvar_RegisterVariable(&r_shadow_glossexponent);
433 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
434 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
435 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
436 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
437 Cvar_RegisterVariable(&r_shadow_portallight);
438 Cvar_RegisterVariable(&r_shadow_projectdistance);
439 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
440 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
441 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
442 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
443 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
444 Cvar_RegisterVariable(&r_shadow_realtime_world);
445 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
446 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
447 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
448 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
449 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
450 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
451 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
452 Cvar_RegisterVariable(&r_shadow_scissor);
453 Cvar_RegisterVariable(&r_shadow_culltriangles);
454 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
455 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
456 Cvar_RegisterVariable(&r_shadow_texture3d);
457 Cvar_RegisterVariable(&gl_ext_separatestencil);
458 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
459 if (gamemode == GAME_TENEBRAE)
461 Cvar_SetValue("r_shadow_gloss", 2);
462 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
464 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
465 R_Shadow_EditLights_Init();
466 r_shadow_worldlightchain = NULL;
467 maxshadowtriangles = 0;
468 shadowelements = NULL;
469 maxshadowvertices = 0;
470 shadowvertex3f = NULL;
478 shadowmarklist = NULL;
480 r_shadow_buffer_numleafpvsbytes = 0;
481 r_shadow_buffer_leafpvs = NULL;
482 r_shadow_buffer_leaflist = NULL;
483 r_shadow_buffer_numsurfacepvsbytes = 0;
484 r_shadow_buffer_surfacepvs = NULL;
485 r_shadow_buffer_surfacelist = NULL;
486 r_shadow_buffer_shadowtrispvs = NULL;
487 r_shadow_buffer_lighttrispvs = NULL;
488 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
491 matrix4x4_t matrix_attenuationxyz =
494 {0.5, 0.0, 0.0, 0.5},
495 {0.0, 0.5, 0.0, 0.5},
496 {0.0, 0.0, 0.5, 0.5},
501 matrix4x4_t matrix_attenuationz =
504 {0.0, 0.0, 0.5, 0.5},
505 {0.0, 0.0, 0.0, 0.5},
506 {0.0, 0.0, 0.0, 0.5},
511 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
513 // make sure shadowelements is big enough for this volume
514 if (maxshadowtriangles < numtriangles)
516 maxshadowtriangles = numtriangles;
518 Mem_Free(shadowelements);
519 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
521 // make sure shadowvertex3f is big enough for this volume
522 if (maxshadowvertices < numvertices)
524 maxshadowvertices = numvertices;
526 Mem_Free(shadowvertex3f);
527 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
531 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
533 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
534 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
535 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
536 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
537 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
539 if (r_shadow_buffer_leafpvs)
540 Mem_Free(r_shadow_buffer_leafpvs);
541 if (r_shadow_buffer_leaflist)
542 Mem_Free(r_shadow_buffer_leaflist);
543 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
544 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
545 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
547 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
549 if (r_shadow_buffer_surfacepvs)
550 Mem_Free(r_shadow_buffer_surfacepvs);
551 if (r_shadow_buffer_surfacelist)
552 Mem_Free(r_shadow_buffer_surfacelist);
553 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
554 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
555 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
557 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
559 if (r_shadow_buffer_shadowtrispvs)
560 Mem_Free(r_shadow_buffer_shadowtrispvs);
561 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
562 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
564 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
566 if (r_shadow_buffer_lighttrispvs)
567 Mem_Free(r_shadow_buffer_lighttrispvs);
568 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
569 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
573 void R_Shadow_PrepareShadowMark(int numtris)
575 // make sure shadowmark is big enough for this volume
576 if (maxshadowmark < numtris)
578 maxshadowmark = numtris;
580 Mem_Free(shadowmark);
582 Mem_Free(shadowmarklist);
583 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
584 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
588 // if shadowmarkcount wrapped we clear the array and adjust accordingly
589 if (shadowmarkcount == 0)
592 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
597 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)
600 int outtriangles = 0, outvertices = 0;
603 float ratio, direction[3], projectvector[3];
605 if (projectdirection)
606 VectorScale(projectdirection, projectdistance, projectvector);
608 VectorClear(projectvector);
610 if (maxvertexupdate < innumvertices)
612 maxvertexupdate = innumvertices;
614 Mem_Free(vertexupdate);
616 Mem_Free(vertexremap);
617 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
618 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
622 if (vertexupdatenum == 0)
625 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
626 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
629 for (i = 0;i < numshadowmarktris;i++)
630 shadowmark[shadowmarktris[i]] = shadowmarkcount;
632 // create the vertices
633 if (projectdirection)
635 for (i = 0;i < numshadowmarktris;i++)
637 element = inelement3i + shadowmarktris[i] * 3;
638 for (j = 0;j < 3;j++)
640 if (vertexupdate[element[j]] != vertexupdatenum)
642 vertexupdate[element[j]] = vertexupdatenum;
643 vertexremap[element[j]] = outvertices;
644 vertex = invertex3f + element[j] * 3;
645 // project one copy of the vertex according to projectvector
646 VectorCopy(vertex, outvertex3f);
647 VectorAdd(vertex, projectvector, (outvertex3f + 3));
656 for (i = 0;i < numshadowmarktris;i++)
658 element = inelement3i + shadowmarktris[i] * 3;
659 for (j = 0;j < 3;j++)
661 if (vertexupdate[element[j]] != vertexupdatenum)
663 vertexupdate[element[j]] = vertexupdatenum;
664 vertexremap[element[j]] = outvertices;
665 vertex = invertex3f + element[j] * 3;
666 // project one copy of the vertex to the sphere radius of the light
667 // (FIXME: would projecting it to the light box be better?)
668 VectorSubtract(vertex, projectorigin, direction);
669 ratio = projectdistance / VectorLength(direction);
670 VectorCopy(vertex, outvertex3f);
671 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
679 if (r_shadow_frontsidecasting.integer)
681 for (i = 0;i < numshadowmarktris;i++)
683 int remappedelement[3];
685 const int *neighbortriangle;
687 markindex = shadowmarktris[i] * 3;
688 element = inelement3i + markindex;
689 neighbortriangle = inneighbor3i + markindex;
690 // output the front and back triangles
691 outelement3i[0] = vertexremap[element[0]];
692 outelement3i[1] = vertexremap[element[1]];
693 outelement3i[2] = vertexremap[element[2]];
694 outelement3i[3] = vertexremap[element[2]] + 1;
695 outelement3i[4] = vertexremap[element[1]] + 1;
696 outelement3i[5] = vertexremap[element[0]] + 1;
700 // output the sides (facing outward from this triangle)
701 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
703 remappedelement[0] = vertexremap[element[0]];
704 remappedelement[1] = vertexremap[element[1]];
705 outelement3i[0] = remappedelement[1];
706 outelement3i[1] = remappedelement[0];
707 outelement3i[2] = remappedelement[0] + 1;
708 outelement3i[3] = remappedelement[1];
709 outelement3i[4] = remappedelement[0] + 1;
710 outelement3i[5] = remappedelement[1] + 1;
715 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
717 remappedelement[1] = vertexremap[element[1]];
718 remappedelement[2] = vertexremap[element[2]];
719 outelement3i[0] = remappedelement[2];
720 outelement3i[1] = remappedelement[1];
721 outelement3i[2] = remappedelement[1] + 1;
722 outelement3i[3] = remappedelement[2];
723 outelement3i[4] = remappedelement[1] + 1;
724 outelement3i[5] = remappedelement[2] + 1;
729 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
731 remappedelement[0] = vertexremap[element[0]];
732 remappedelement[2] = vertexremap[element[2]];
733 outelement3i[0] = remappedelement[0];
734 outelement3i[1] = remappedelement[2];
735 outelement3i[2] = remappedelement[2] + 1;
736 outelement3i[3] = remappedelement[0];
737 outelement3i[4] = remappedelement[2] + 1;
738 outelement3i[5] = remappedelement[0] + 1;
747 for (i = 0;i < numshadowmarktris;i++)
749 int remappedelement[3];
751 const int *neighbortriangle;
753 markindex = shadowmarktris[i] * 3;
754 element = inelement3i + markindex;
755 neighbortriangle = inneighbor3i + markindex;
756 // output the front and back triangles
757 outelement3i[0] = vertexremap[element[2]];
758 outelement3i[1] = vertexremap[element[1]];
759 outelement3i[2] = vertexremap[element[0]];
760 outelement3i[3] = vertexremap[element[0]] + 1;
761 outelement3i[4] = vertexremap[element[1]] + 1;
762 outelement3i[5] = vertexremap[element[2]] + 1;
766 // output the sides (facing outward from this triangle)
767 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
769 remappedelement[0] = vertexremap[element[0]];
770 remappedelement[1] = vertexremap[element[1]];
771 outelement3i[0] = remappedelement[0];
772 outelement3i[1] = remappedelement[1];
773 outelement3i[2] = remappedelement[1] + 1;
774 outelement3i[3] = remappedelement[0];
775 outelement3i[4] = remappedelement[1] + 1;
776 outelement3i[5] = remappedelement[0] + 1;
781 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
783 remappedelement[1] = vertexremap[element[1]];
784 remappedelement[2] = vertexremap[element[2]];
785 outelement3i[0] = remappedelement[1];
786 outelement3i[1] = remappedelement[2];
787 outelement3i[2] = remappedelement[2] + 1;
788 outelement3i[3] = remappedelement[1];
789 outelement3i[4] = remappedelement[2] + 1;
790 outelement3i[5] = remappedelement[1] + 1;
795 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
797 remappedelement[0] = vertexremap[element[0]];
798 remappedelement[2] = vertexremap[element[2]];
799 outelement3i[0] = remappedelement[2];
800 outelement3i[1] = remappedelement[0];
801 outelement3i[2] = remappedelement[0] + 1;
802 outelement3i[3] = remappedelement[2];
803 outelement3i[4] = remappedelement[0] + 1;
804 outelement3i[5] = remappedelement[2] + 1;
812 *outnumvertices = outvertices;
816 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)
819 if (projectdistance < 0.1)
821 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
824 if (!numverts || !nummarktris)
826 // make sure shadowelements is big enough for this volume
827 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
828 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
829 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
830 r_refdef.stats.lights_dynamicshadowtriangles += tris;
831 R_Shadow_RenderVolume(outverts, tris, shadowvertex3f, shadowelements);
834 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)
840 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
842 tend = firsttriangle + numtris;
843 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
845 // surface box entirely inside light box, no box cull
846 if (projectdirection)
848 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
850 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
851 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
852 shadowmarklist[numshadowmark++] = t;
857 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
858 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
859 shadowmarklist[numshadowmark++] = t;
864 // surface box not entirely inside light box, cull each triangle
865 if (projectdirection)
867 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
869 v[0] = invertex3f + e[0] * 3;
870 v[1] = invertex3f + e[1] * 3;
871 v[2] = invertex3f + e[2] * 3;
872 TriangleNormal(v[0], v[1], v[2], normal);
873 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
874 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
875 shadowmarklist[numshadowmark++] = t;
880 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
882 v[0] = invertex3f + e[0] * 3;
883 v[1] = invertex3f + e[1] * 3;
884 v[2] = invertex3f + e[2] * 3;
885 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
886 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
887 shadowmarklist[numshadowmark++] = t;
893 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
895 if (r_shadow_compilingrtlight)
897 // if we're compiling an rtlight, capture the mesh
898 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
901 r_refdef.stats.lights_shadowtriangles += numtriangles;
903 R_Mesh_VertexPointer(vertex3f, 0, 0);
904 GL_LockArrays(0, numvertices);
905 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
907 // decrement stencil if backface is behind depthbuffer
908 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
909 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
910 R_Mesh_Draw(0, numvertices, numtriangles, element3i, 0, 0);
911 // increment stencil if frontface is behind depthbuffer
912 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
913 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
915 R_Mesh_Draw(0, numvertices, numtriangles, element3i, 0, 0);
920 static unsigned char R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
922 float dist = sqrt(x*x+y*y+z*z);
923 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
924 return (unsigned char)bound(0, intensity * 256.0f, 255);
927 static void R_Shadow_MakeTextures(void)
930 float intensity, dist;
932 unsigned int palette[256];
933 R_FreeTexturePool(&r_shadow_texturepool);
934 r_shadow_texturepool = R_AllocTexturePool();
935 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
936 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
937 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
938 for (x = 0;x < 256;x++)
939 palette[x] = x * 0x01010101;
940 data = (unsigned char *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE));
941 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
942 for (x = 0;x <= ATTENTABLESIZE;x++)
944 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
945 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
946 r_shadow_attentable[x] = bound(0, intensity, 1);
948 // 1D gradient texture
949 for (x = 0;x < ATTEN1DSIZE;x++)
950 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
951 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, data, TEXTYPE_PALETTE, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, palette);
953 for (y = 0;y < ATTEN2DSIZE;y++)
954 for (x = 0;x < ATTEN2DSIZE;x++)
955 data[y*ATTEN2DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), 0);
956 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_PALETTE, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, palette);
958 if (r_shadow_texture3d.integer && gl_texture3d)
960 for (z = 0;z < ATTEN3DSIZE;z++)
961 for (y = 0;y < ATTEN3DSIZE;y++)
962 for (x = 0;x < ATTEN3DSIZE;x++)
963 data[(z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375));
964 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_PALETTE, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, palette);
967 r_shadow_attenuation3dtexture = NULL;
971 void R_Shadow_ValidateCvars(void)
973 if (r_shadow_texture3d.integer && !gl_texture3d)
974 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
975 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
976 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
977 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
978 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
981 // light currently being rendered
982 rtlight_t *r_shadow_rtlight;
984 // this is the location of the light in entity space
985 vec3_t r_shadow_entitylightorigin;
986 // this transforms entity coordinates to light filter cubemap coordinates
987 // (also often used for other purposes)
988 matrix4x4_t r_shadow_entitytolight;
989 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
990 // of attenuation texturing in full 3D (Z result often ignored)
991 matrix4x4_t r_shadow_entitytoattenuationxyz;
992 // this transforms only the Z to S, and T is always 0.5
993 matrix4x4_t r_shadow_entitytoattenuationz;
995 void R_Shadow_RenderMode_Begin(void)
997 R_Shadow_ValidateCvars();
999 if (!r_shadow_attenuation2dtexture
1000 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1001 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1002 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1003 R_Shadow_MakeTextures();
1006 R_Mesh_ColorPointer(NULL, 0, 0);
1007 R_Mesh_ResetTextureState();
1008 GL_BlendFunc(GL_ONE, GL_ZERO);
1010 GL_DepthMask(false);
1011 GL_Color(0, 0, 0, 1);
1012 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1014 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1016 if (gl_ext_separatestencil.integer)
1017 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
1018 else if (gl_ext_stenciltwoside.integer)
1019 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
1021 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
1023 if (r_glsl.integer && gl_support_fragment_shader)
1024 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1025 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1026 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1028 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1031 void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
1033 r_shadow_rtlight = rtlight;
1036 void R_Shadow_RenderMode_Reset(void)
1039 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1041 qglUseProgramObjectARB(0);CHECKGLERROR
1043 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1045 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1047 R_Mesh_ColorPointer(NULL, 0, 0);
1048 R_Mesh_ResetTextureState();
1050 GL_DepthMask(false);
1051 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1052 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1053 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1054 qglStencilMask(~0);CHECKGLERROR
1055 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1056 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1057 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
1058 GL_Color(1, 1, 1, 1);
1059 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
1060 GL_BlendFunc(GL_ONE, GL_ZERO);
1063 void R_Shadow_RenderMode_StencilShadowVolumes(void)
1066 R_Shadow_RenderMode_Reset();
1067 GL_ColorMask(0, 0, 0, 0);
1068 qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1069 qglDepthFunc(GL_LESS);CHECKGLERROR
1070 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1071 r_shadow_rendermode = r_shadow_shadowingrendermode;
1072 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SEPARATESTENCIL)
1074 GL_CullFace(GL_NONE);
1075 qglStencilOpSeparate(GL_BACK, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR // quake is backwards, this is front faces
1076 qglStencilOpSeparate(GL_FRONT, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR // quake is backwards, this is back faces
1078 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1080 GL_CullFace(GL_NONE);
1081 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1082 qglActiveStencilFaceEXT(GL_BACK);CHECKGLERROR // quake is backwards, this is front faces
1083 qglStencilMask(~0);CHECKGLERROR
1084 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1085 qglActiveStencilFaceEXT(GL_FRONT);CHECKGLERROR // quake is backwards, this is back faces
1086 qglStencilMask(~0);CHECKGLERROR
1087 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1089 GL_Clear(GL_STENCIL_BUFFER_BIT);
1090 r_refdef.stats.lights_clears++;
1093 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
1096 R_Shadow_RenderMode_Reset();
1097 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1100 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1104 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1105 // only draw light where this geometry was already rendered AND the
1106 // stencil is 128 (values other than this mean shadow)
1107 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1109 r_shadow_rendermode = r_shadow_lightingrendermode;
1110 // do global setup needed for the chosen lighting mode
1111 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1113 R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
1114 R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
1115 R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
1116 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_rtlight->currentcubemap)); // light filter
1117 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
1118 R_Mesh_TexBind(5, R_GetTexture(r_texture_white)); // pants
1119 R_Mesh_TexBind(6, R_GetTexture(r_texture_white)); // shirt
1120 R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); // lightmap
1121 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); // deluxemap
1122 R_Mesh_TexBind(9, R_GetTexture(r_texture_black)); // glow
1123 //R_Mesh_TexMatrix(3, r_shadow_entitytolight); // light filter matrix
1124 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1125 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1130 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1133 R_Shadow_RenderMode_Reset();
1134 GL_BlendFunc(GL_ONE, GL_ONE);
1135 GL_DepthTest(r_showshadowvolumes.integer < 2);
1136 GL_Color(0.0, 0.0125 * r_view.colorscale, 0.1 * r_view.colorscale, 1);
1137 qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1138 GL_CullFace(GL_NONE);
1139 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1142 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1145 R_Shadow_RenderMode_Reset();
1146 GL_BlendFunc(GL_ONE, GL_ONE);
1147 GL_DepthTest(r_showlighting.integer < 2);
1148 GL_Color(0.1 * r_view.colorscale, 0.0125 * r_view.colorscale, 0, 1);
1151 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1155 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1156 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1158 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1161 void R_Shadow_RenderMode_End(void)
1164 R_Shadow_RenderMode_Reset();
1165 R_Shadow_RenderMode_ActiveLight(NULL);
1167 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1168 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1171 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1173 int i, ix1, iy1, ix2, iy2;
1174 float x1, y1, x2, y2;
1177 mplane_t planes[11];
1178 float vertex3f[256*3];
1180 // if view is inside the light box, just say yes it's visible
1181 if (BoxesOverlap(r_view.origin, r_view.origin, mins, maxs))
1183 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1187 // create a temporary brush describing the area the light can affect in worldspace
1188 VectorNegate(r_view.frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -r_view.frustum[0].dist;
1189 VectorNegate(r_view.frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -r_view.frustum[1].dist;
1190 VectorNegate(r_view.frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -r_view.frustum[2].dist;
1191 VectorNegate(r_view.frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -r_view.frustum[3].dist;
1192 VectorNegate(r_view.frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -r_view.frustum[4].dist;
1193 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1194 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1195 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1196 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1197 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1198 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1200 // turn the brush into a mesh
1201 memset(&mesh, 0, sizeof(rmesh_t));
1202 mesh.maxvertices = 256;
1203 mesh.vertex3f = vertex3f;
1204 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1205 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1207 // if that mesh is empty, the light is not visible at all
1208 if (!mesh.numvertices)
1211 if (!r_shadow_scissor.integer)
1214 // if that mesh is not empty, check what area of the screen it covers
1215 x1 = y1 = x2 = y2 = 0;
1217 //Con_Printf("%i vertices to transform...\n", mesh.numvertices);
1218 for (i = 0;i < mesh.numvertices;i++)
1220 VectorCopy(mesh.vertex3f + i * 3, v);
1221 GL_TransformToScreen(v, v2);
1222 //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]);
1225 if (x1 > v2[0]) x1 = v2[0];
1226 if (x2 < v2[0]) x2 = v2[0];
1227 if (y1 > v2[1]) y1 = v2[1];
1228 if (y2 < v2[1]) y2 = v2[1];
1237 // now convert the scissor rectangle to integer screen coordinates
1238 ix1 = (int)(x1 - 1.0f);
1239 iy1 = (int)(y1 - 1.0f);
1240 ix2 = (int)(x2 + 1.0f);
1241 iy2 = (int)(y2 + 1.0f);
1242 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1244 // clamp it to the screen
1245 if (ix1 < r_view.x) ix1 = r_view.x;
1246 if (iy1 < r_view.y) iy1 = r_view.y;
1247 if (ix2 > r_view.x + r_view.width) ix2 = r_view.x + r_view.width;
1248 if (iy2 > r_view.y + r_view.height) iy2 = r_view.y + r_view.height;
1250 // if it is inside out, it's not visible
1251 if (ix2 <= ix1 || iy2 <= iy1)
1254 // the light area is visible, set up the scissor rectangle
1255 GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1256 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1257 //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1258 r_refdef.stats.lights_scissored++;
1262 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1264 float *vertex3f = rsurface_vertex3f + 3 * firstvertex;
1265 float *normal3f = rsurface_normal3f + 3 * firstvertex;
1266 float *color4f = rsurface_array_color4f + 4 * firstvertex;
1267 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1268 if (r_textureunits.integer >= 3)
1270 if (VectorLength2(diffusecolor) > 0)
1272 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1274 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1275 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1276 if ((dot = DotProduct(n, v)) < 0)
1278 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1279 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1282 VectorCopy(ambientcolor, color4f);
1283 if (r_refdef.fogenabled)
1285 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1286 VectorScale(color4f, f, color4f);
1293 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1295 VectorCopy(ambientcolor, color4f);
1296 if (r_refdef.fogenabled)
1299 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1300 f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1301 VectorScale(color4f, f, color4f);
1307 else if (r_textureunits.integer >= 2)
1309 if (VectorLength2(diffusecolor) > 0)
1311 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1313 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1314 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1316 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1317 if ((dot = DotProduct(n, v)) < 0)
1319 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1320 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1321 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1322 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1326 color4f[0] = ambientcolor[0] * distintensity;
1327 color4f[1] = ambientcolor[1] * distintensity;
1328 color4f[2] = ambientcolor[2] * distintensity;
1330 if (r_refdef.fogenabled)
1332 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1333 VectorScale(color4f, f, color4f);
1337 VectorClear(color4f);
1343 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1345 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1346 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1348 color4f[0] = ambientcolor[0] * distintensity;
1349 color4f[1] = ambientcolor[1] * distintensity;
1350 color4f[2] = ambientcolor[2] * distintensity;
1351 if (r_refdef.fogenabled)
1353 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1354 VectorScale(color4f, f, color4f);
1358 VectorClear(color4f);
1365 if (VectorLength2(diffusecolor) > 0)
1367 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1369 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1370 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1372 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1373 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1374 if ((dot = DotProduct(n, v)) < 0)
1376 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1377 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1378 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1379 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1383 color4f[0] = ambientcolor[0] * distintensity;
1384 color4f[1] = ambientcolor[1] * distintensity;
1385 color4f[2] = ambientcolor[2] * distintensity;
1387 if (r_refdef.fogenabled)
1389 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1390 VectorScale(color4f, f, color4f);
1394 VectorClear(color4f);
1400 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1402 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1403 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1405 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1406 color4f[0] = ambientcolor[0] * distintensity;
1407 color4f[1] = ambientcolor[1] * distintensity;
1408 color4f[2] = ambientcolor[2] * distintensity;
1409 if (r_refdef.fogenabled)
1411 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1412 VectorScale(color4f, f, color4f);
1416 VectorClear(color4f);
1423 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1425 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1428 float *out3f = rsurface_array_texcoord3f + 3 * firstvertex;
1429 const float *vertex3f = rsurface_vertex3f + 3 * firstvertex;
1430 const float *svector3f = rsurface_svector3f + 3 * firstvertex;
1431 const float *tvector3f = rsurface_tvector3f + 3 * firstvertex;
1432 const float *normal3f = rsurface_normal3f + 3 * firstvertex;
1434 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1436 VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1437 // the cubemap normalizes this for us
1438 out3f[0] = DotProduct(svector3f, lightdir);
1439 out3f[1] = DotProduct(tvector3f, lightdir);
1440 out3f[2] = DotProduct(normal3f, lightdir);
1444 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1447 float *out3f = rsurface_array_texcoord3f + 3 * firstvertex;
1448 const float *vertex3f = rsurface_vertex3f + 3 * firstvertex;
1449 const float *svector3f = rsurface_svector3f + 3 * firstvertex;
1450 const float *tvector3f = rsurface_tvector3f + 3 * firstvertex;
1451 const float *normal3f = rsurface_normal3f + 3 * firstvertex;
1452 float lightdir[3], eyedir[3], halfdir[3];
1453 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1455 VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1456 VectorNormalize(lightdir);
1457 VectorSubtract(rsurface_modelorg, vertex3f, eyedir);
1458 VectorNormalize(eyedir);
1459 VectorAdd(lightdir, eyedir, halfdir);
1460 // the cubemap normalizes this for us
1461 out3f[0] = DotProduct(svector3f, halfdir);
1462 out3f[1] = DotProduct(tvector3f, halfdir);
1463 out3f[2] = DotProduct(normal3f, halfdir);
1467 static void R_Shadow_RenderLighting_VisibleLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, 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 ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
1469 // used to display how many times a surface is lit for level design purposes
1470 GL_Color(0.1 * r_view.colorscale, 0.025 * r_view.colorscale, 0, 1);
1471 R_Mesh_ColorPointer(NULL, 0, 0);
1472 R_Mesh_ResetTextureState();
1473 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1476 static void R_Shadow_RenderLighting_Light_GLSL(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, 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 ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
1478 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1479 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale);
1480 R_Mesh_TexCoordPointer(0, 2, rsurface_model->surfmesh.data_texcoordtexture2f, rsurface_model->surfmesh.vbo, rsurface_model->surfmesh.vbooffset_texcoordtexture2f);
1481 R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f, rsurface_svector3f_bufferobject, rsurface_svector3f_bufferoffset);
1482 R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f, rsurface_tvector3f_bufferobject, rsurface_tvector3f_bufferoffset);
1483 R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f, rsurface_normal3f_bufferobject, rsurface_normal3f_bufferoffset);
1484 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1486 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1488 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1489 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1491 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1495 static void R_Shadow_RenderLighting_Light_Dot3_Finalize(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, float r, float g, float b)
1497 // shared final code for all the dot3 layers
1499 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1500 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1502 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1503 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1507 static void R_Shadow_RenderLighting_Light_Dot3_AmbientPass(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
1510 // colorscale accounts for how much we multiply the brightness
1513 // mult is how many times the final pass of the lighting will be
1514 // performed to get more brightness than otherwise possible.
1516 // Limit mult to 64 for sanity sake.
1518 if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1520 // 3 3D combine path (Geforce3, Radeon 8500)
1521 memset(&m, 0, sizeof(m));
1522 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1523 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1524 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1525 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1526 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1527 m.tex[1] = R_GetTexture(basetexture);
1528 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1529 m.pointer_texcoord_bufferobject[1] = rsurface_model->surfmesh.vbo;
1530 m.pointer_texcoord_bufferoffset[1] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1531 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1532 m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1533 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1534 m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject;
1535 m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset;
1536 m.texmatrix[2] = r_shadow_entitytolight;
1537 GL_BlendFunc(GL_ONE, GL_ONE);
1539 else if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1541 // 2 3D combine path (Geforce3, original Radeon)
1542 memset(&m, 0, sizeof(m));
1543 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1544 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1545 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1546 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1547 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1548 m.tex[1] = R_GetTexture(basetexture);
1549 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1550 m.pointer_texcoord_bufferobject[1] = rsurface_model->surfmesh.vbo;
1551 m.pointer_texcoord_bufferoffset[1] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1552 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1553 GL_BlendFunc(GL_ONE, GL_ONE);
1555 else if (r_textureunits.integer >= 4 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1557 // 4 2D combine path (Geforce3, Radeon 8500)
1558 memset(&m, 0, sizeof(m));
1559 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1560 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1561 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1562 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1563 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1564 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1565 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1566 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1567 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1568 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1569 m.tex[2] = R_GetTexture(basetexture);
1570 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1571 m.pointer_texcoord_bufferobject[2] = rsurface_model->surfmesh.vbo;
1572 m.pointer_texcoord_bufferoffset[2] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1573 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1574 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1576 m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1577 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1578 m.pointer_texcoord_bufferobject[3] = rsurface_vertex3f_bufferobject;
1579 m.pointer_texcoord_bufferoffset[3] = rsurface_vertex3f_bufferoffset;
1580 m.texmatrix[3] = r_shadow_entitytolight;
1582 GL_BlendFunc(GL_ONE, GL_ONE);
1584 else if (r_textureunits.integer >= 3 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1586 // 3 2D combine path (Geforce3, original Radeon)
1587 memset(&m, 0, sizeof(m));
1588 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1589 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1590 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1591 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1592 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1593 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1594 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1595 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1596 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1597 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1598 m.tex[2] = R_GetTexture(basetexture);
1599 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1600 m.pointer_texcoord_bufferobject[2] = rsurface_model->surfmesh.vbo;
1601 m.pointer_texcoord_bufferoffset[2] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1602 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1603 GL_BlendFunc(GL_ONE, GL_ONE);
1607 // 2/2/2 2D combine path (any dot3 card)
1608 memset(&m, 0, sizeof(m));
1609 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1610 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1611 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1612 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1613 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1614 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1615 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1616 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1617 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1618 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1619 R_Mesh_TextureState(&m);
1620 GL_ColorMask(0,0,0,1);
1621 GL_BlendFunc(GL_ONE, GL_ZERO);
1622 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1625 memset(&m, 0, sizeof(m));
1626 m.tex[0] = R_GetTexture(basetexture);
1627 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1628 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1629 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1630 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1631 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1633 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1634 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1635 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1636 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1637 m.texmatrix[1] = r_shadow_entitytolight;
1639 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1641 // this final code is shared
1642 R_Mesh_TextureState(&m);
1643 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1646 static void R_Shadow_RenderLighting_Light_Dot3_DiffusePass(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, rtexture_t *basetexture, rtexture_t *normalmaptexture, float colorscale)
1649 // colorscale accounts for how much we multiply the brightness
1652 // mult is how many times the final pass of the lighting will be
1653 // performed to get more brightness than otherwise possible.
1655 // Limit mult to 64 for sanity sake.
1657 // generate normalization cubemap texcoords
1658 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1659 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1661 // 3/2 3D combine path (Geforce3, Radeon 8500)
1662 memset(&m, 0, sizeof(m));
1663 m.tex[0] = R_GetTexture(normalmaptexture);
1664 m.texcombinergb[0] = GL_REPLACE;
1665 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1666 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1667 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1668 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1669 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1670 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1671 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1672 m.pointer_texcoord_bufferobject[1] = 0;
1673 m.pointer_texcoord_bufferoffset[1] = 0;
1674 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1675 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1676 m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject;
1677 m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset;
1678 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1679 R_Mesh_TextureState(&m);
1680 GL_ColorMask(0,0,0,1);
1681 GL_BlendFunc(GL_ONE, GL_ZERO);
1682 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1685 memset(&m, 0, sizeof(m));
1686 m.tex[0] = R_GetTexture(basetexture);
1687 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1688 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1689 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1690 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1691 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1693 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1694 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1695 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1696 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1697 m.texmatrix[1] = r_shadow_entitytolight;
1699 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1701 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1703 // 1/2/2 3D combine path (original Radeon)
1704 memset(&m, 0, sizeof(m));
1705 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1706 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1707 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1708 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1709 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1710 R_Mesh_TextureState(&m);
1711 GL_ColorMask(0,0,0,1);
1712 GL_BlendFunc(GL_ONE, GL_ZERO);
1713 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1716 memset(&m, 0, sizeof(m));
1717 m.tex[0] = R_GetTexture(normalmaptexture);
1718 m.texcombinergb[0] = GL_REPLACE;
1719 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1720 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1721 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1722 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1723 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1724 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1725 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1726 m.pointer_texcoord_bufferobject[1] = 0;
1727 m.pointer_texcoord_bufferoffset[1] = 0;
1728 R_Mesh_TextureState(&m);
1729 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1730 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1733 memset(&m, 0, sizeof(m));
1734 m.tex[0] = R_GetTexture(basetexture);
1735 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1736 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1737 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1738 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1739 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1741 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1742 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1743 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1744 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1745 m.texmatrix[1] = r_shadow_entitytolight;
1747 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1749 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1751 // 2/2 3D combine path (original Radeon)
1752 memset(&m, 0, sizeof(m));
1753 m.tex[0] = R_GetTexture(normalmaptexture);
1754 m.texcombinergb[0] = GL_REPLACE;
1755 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1756 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1757 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1758 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1759 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1760 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1761 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1762 m.pointer_texcoord_bufferobject[1] = 0;
1763 m.pointer_texcoord_bufferoffset[1] = 0;
1764 R_Mesh_TextureState(&m);
1765 GL_ColorMask(0,0,0,1);
1766 GL_BlendFunc(GL_ONE, GL_ZERO);
1767 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1770 memset(&m, 0, sizeof(m));
1771 m.tex[0] = R_GetTexture(basetexture);
1772 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1773 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1774 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1775 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1776 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1777 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1778 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1779 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1780 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1781 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1783 else if (r_textureunits.integer >= 4)
1785 // 4/2 2D combine path (Geforce3, Radeon 8500)
1786 memset(&m, 0, sizeof(m));
1787 m.tex[0] = R_GetTexture(normalmaptexture);
1788 m.texcombinergb[0] = GL_REPLACE;
1789 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1790 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1791 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1792 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1793 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1794 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1795 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1796 m.pointer_texcoord_bufferobject[1] = 0;
1797 m.pointer_texcoord_bufferoffset[1] = 0;
1798 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1799 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1800 m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject;
1801 m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset;
1802 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1803 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1804 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1805 m.pointer_texcoord_bufferobject[3] = rsurface_vertex3f_bufferobject;
1806 m.pointer_texcoord_bufferoffset[3] = rsurface_vertex3f_bufferoffset;
1807 m.texmatrix[3] = r_shadow_entitytoattenuationz;
1808 R_Mesh_TextureState(&m);
1809 GL_ColorMask(0,0,0,1);
1810 GL_BlendFunc(GL_ONE, GL_ZERO);
1811 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1814 memset(&m, 0, sizeof(m));
1815 m.tex[0] = R_GetTexture(basetexture);
1816 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1817 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1818 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1819 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1820 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1822 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1823 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1824 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1825 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1826 m.texmatrix[1] = r_shadow_entitytolight;
1828 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1832 // 2/2/2 2D combine path (any dot3 card)
1833 memset(&m, 0, sizeof(m));
1834 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1835 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1836 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1837 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1838 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1839 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1840 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1841 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1842 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1843 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1844 R_Mesh_TextureState(&m);
1845 GL_ColorMask(0,0,0,1);
1846 GL_BlendFunc(GL_ONE, GL_ZERO);
1847 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1850 memset(&m, 0, sizeof(m));
1851 m.tex[0] = R_GetTexture(normalmaptexture);
1852 m.texcombinergb[0] = GL_REPLACE;
1853 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1854 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1855 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1856 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1857 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1858 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1859 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1860 m.pointer_texcoord_bufferobject[1] = 0;
1861 m.pointer_texcoord_bufferoffset[1] = 0;
1862 R_Mesh_TextureState(&m);
1863 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1864 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1867 memset(&m, 0, sizeof(m));
1868 m.tex[0] = R_GetTexture(basetexture);
1869 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1870 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1871 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1872 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1873 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1875 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1876 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1877 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1878 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1879 m.texmatrix[1] = r_shadow_entitytolight;
1881 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1883 // this final code is shared
1884 R_Mesh_TextureState(&m);
1885 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1888 static void R_Shadow_RenderLighting_Light_Dot3_SpecularPass(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale)
1890 float glossexponent;
1892 // FIXME: detect blendsquare!
1893 //if (!gl_support_blendsquare)
1896 // generate normalization cubemap texcoords
1897 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1898 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1900 // 2/0/0/1/2 3D combine blendsquare path
1901 memset(&m, 0, sizeof(m));
1902 m.tex[0] = R_GetTexture(normalmaptexture);
1903 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1904 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1905 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1906 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1907 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1908 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1909 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1910 m.pointer_texcoord_bufferobject[1] = 0;
1911 m.pointer_texcoord_bufferoffset[1] = 0;
1912 R_Mesh_TextureState(&m);
1913 GL_ColorMask(0,0,0,1);
1914 // this squares the result
1915 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1916 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1918 // second and third pass
1919 R_Mesh_ResetTextureState();
1920 // square alpha in framebuffer a few times to make it shiny
1921 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1922 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1923 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1926 memset(&m, 0, sizeof(m));
1927 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1928 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1929 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1930 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1931 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1932 R_Mesh_TextureState(&m);
1933 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1934 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1937 memset(&m, 0, sizeof(m));
1938 m.tex[0] = R_GetTexture(glosstexture);
1939 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1940 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1941 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1942 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1943 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1945 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1946 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1947 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1948 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1949 m.texmatrix[1] = r_shadow_entitytolight;
1951 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1953 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1955 // 2/0/0/2 3D combine blendsquare path
1956 memset(&m, 0, sizeof(m));
1957 m.tex[0] = R_GetTexture(normalmaptexture);
1958 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1959 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1960 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1961 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1962 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1963 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1964 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1965 m.pointer_texcoord_bufferobject[1] = 0;
1966 m.pointer_texcoord_bufferoffset[1] = 0;
1967 R_Mesh_TextureState(&m);
1968 GL_ColorMask(0,0,0,1);
1969 // this squares the result
1970 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1971 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1973 // second and third pass
1974 R_Mesh_ResetTextureState();
1975 // square alpha in framebuffer a few times to make it shiny
1976 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1977 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1978 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1981 memset(&m, 0, sizeof(m));
1982 m.tex[0] = R_GetTexture(glosstexture);
1983 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1984 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1985 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1986 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1987 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1988 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1989 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1990 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1991 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1992 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1996 // 2/0/0/2/2 2D combine blendsquare path
1997 memset(&m, 0, sizeof(m));
1998 m.tex[0] = R_GetTexture(normalmaptexture);
1999 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
2000 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
2001 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
2002 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
2003 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2004 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2005 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
2006 m.pointer_texcoord_bufferobject[1] = 0;
2007 m.pointer_texcoord_bufferoffset[1] = 0;
2008 R_Mesh_TextureState(&m);
2009 GL_ColorMask(0,0,0,1);
2010 // this squares the result
2011 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2012 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2014 // second and third pass
2015 R_Mesh_ResetTextureState();
2016 // square alpha in framebuffer a few times to make it shiny
2017 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2018 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2019 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2022 memset(&m, 0, sizeof(m));
2023 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2024 m.pointer_texcoord3f[0] = rsurface_vertex3f;
2025 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
2026 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
2027 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2028 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2029 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2030 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
2031 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
2032 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2033 R_Mesh_TextureState(&m);
2034 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2035 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2038 memset(&m, 0, sizeof(m));
2039 m.tex[0] = R_GetTexture(glosstexture);
2040 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
2041 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
2042 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
2043 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
2044 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
2046 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
2047 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2048 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
2049 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
2050 m.texmatrix[1] = r_shadow_entitytolight;
2052 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2054 // this final code is shared
2055 R_Mesh_TextureState(&m);
2056 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
2059 static void R_Shadow_RenderLighting_Light_Dot3(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, 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 ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
2061 // ARB path (any Geforce, any Radeon)
2062 qboolean doambient = ambientscale > 0;
2063 qboolean dodiffuse = diffusescale > 0;
2064 qboolean dospecular = specularscale > 0;
2065 if (!doambient && !dodiffuse && !dospecular)
2067 R_Mesh_ColorPointer(NULL, 0, 0);
2069 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, ambientscale * r_view.colorscale);
2071 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_view.colorscale);
2075 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, ambientscale * r_view.colorscale);
2077 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_view.colorscale);
2082 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, ambientscale * r_view.colorscale);
2084 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_view.colorscale);
2087 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale);
2090 void R_Shadow_RenderLighting_Light_Vertex_Pass(const model_t *model, int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, vec3_t diffusecolor2, vec3_t ambientcolor2)
2097 int newnumtriangles;
2101 int newelements[4096*3];
2102 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2103 for (renders = 0;renders < 64;renders++)
2108 newnumtriangles = 0;
2110 // due to low fillrate on the cards this vertex lighting path is
2111 // designed for, we manually cull all triangles that do not
2112 // contain a lit vertex
2113 // this builds batches of triangles from multiple surfaces and
2114 // renders them at once
2115 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2117 if (VectorLength2(rsurface_array_color4f + e[0] * 4) + VectorLength2(rsurface_array_color4f + e[1] * 4) + VectorLength2(rsurface_array_color4f + e[2] * 4) >= 0.01)
2119 if (newnumtriangles)
2121 newfirstvertex = min(newfirstvertex, e[0]);
2122 newlastvertex = max(newlastvertex, e[0]);
2126 newfirstvertex = e[0];
2127 newlastvertex = e[0];
2129 newfirstvertex = min(newfirstvertex, e[1]);
2130 newlastvertex = max(newlastvertex, e[1]);
2131 newfirstvertex = min(newfirstvertex, e[2]);
2132 newlastvertex = max(newlastvertex, e[2]);
2138 if (newnumtriangles >= (int)(sizeof(newelements)/sizeof(float[3])))
2140 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2141 newnumtriangles = 0;
2147 if (newnumtriangles >= 1)
2149 // if all triangles are included, use the original array to take advantage of the bufferobject if possible
2150 if (newnumtriangles == numtriangles)
2151 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2153 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2156 // if we couldn't find any lit triangles, exit early
2159 // now reduce the intensity for the next overbright pass
2160 // we have to clamp to 0 here incase the drivers have improper
2161 // handling of negative colors
2162 // (some old drivers even have improper handling of >1 color)
2164 for (i = 0, c = rsurface_array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2166 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2168 c[0] = max(0, c[0] - 1);
2169 c[1] = max(0, c[1] - 1);
2170 c[2] = max(0, c[2] - 1);
2182 static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, 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 ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
2184 // OpenGL 1.1 path (anything)
2185 model_t *model = rsurface_entity->model;
2186 float ambientcolorbase[3], diffusecolorbase[3];
2187 float ambientcolorpants[3], diffusecolorpants[3];
2188 float ambientcolorshirt[3], diffusecolorshirt[3];
2190 VectorScale(lightcolorbase, ambientscale * 2 * r_view.colorscale, ambientcolorbase);
2191 VectorScale(lightcolorbase, diffusescale * 2 * r_view.colorscale, diffusecolorbase);
2192 VectorScale(lightcolorpants, ambientscale * 2 * r_view.colorscale, ambientcolorpants);
2193 VectorScale(lightcolorpants, diffusescale * 2 * r_view.colorscale, diffusecolorpants);
2194 VectorScale(lightcolorshirt, ambientscale * 2 * r_view.colorscale, ambientcolorshirt);
2195 VectorScale(lightcolorshirt, diffusescale * 2 * r_view.colorscale, diffusecolorshirt);
2196 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2197 R_Mesh_ColorPointer(rsurface_array_color4f, 0, 0);
2198 memset(&m, 0, sizeof(m));
2199 m.tex[0] = R_GetTexture(basetexture);
2200 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
2201 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
2202 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
2203 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
2204 if (r_textureunits.integer >= 2)
2207 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2208 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2209 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2210 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
2211 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
2212 if (r_textureunits.integer >= 3)
2214 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2215 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2216 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2217 m.pointer_texcoord3f[2] = rsurface_vertex3f;
2218 m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject;
2219 m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset;
2222 R_Mesh_TextureState(&m);
2223 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2224 R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorbase, ambientcolorbase);
2227 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2228 R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorpants, ambientcolorpants);
2232 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2233 R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorshirt, ambientcolorshirt);
2237 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset)
2239 float ambientscale, diffusescale, specularscale;
2240 // FIXME: support MATERIALFLAG_NODEPTHTEST
2241 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2242 // calculate colors to render this texture with
2243 lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * rsurface_entity->colormod[0] * rsurface_texture->currentalpha;
2244 lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * rsurface_entity->colormod[1] * rsurface_texture->currentalpha;
2245 lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * rsurface_entity->colormod[2] * rsurface_texture->currentalpha;
2246 ambientscale = r_shadow_rtlight->ambientscale;
2247 diffusescale = r_shadow_rtlight->diffusescale;
2248 specularscale = r_shadow_rtlight->specularscale * rsurface_texture->specularscale;
2249 if (!r_shadow_usenormalmap.integer)
2251 ambientscale += 1.0f * diffusescale;
2255 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2257 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
2258 GL_CullFace((rsurface_texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
2259 if (rsurface_texture->colormapping)
2261 qboolean dopants = rsurface_texture->currentskinframe->pants != NULL && VectorLength2(rsurface_entity->colormap_pantscolor) >= (1.0f / 1048576.0f);
2262 qboolean doshirt = rsurface_texture->currentskinframe->shirt != NULL && VectorLength2(rsurface_entity->colormap_shirtcolor) >= (1.0f / 1048576.0f);
2265 lightcolorpants[0] = lightcolorbase[0] * rsurface_entity->colormap_pantscolor[0];
2266 lightcolorpants[1] = lightcolorbase[1] * rsurface_entity->colormap_pantscolor[1];
2267 lightcolorpants[2] = lightcolorbase[2] * rsurface_entity->colormap_pantscolor[2];
2270 VectorClear(lightcolorpants);
2273 lightcolorshirt[0] = lightcolorbase[0] * rsurface_entity->colormap_shirtcolor[0];
2274 lightcolorshirt[1] = lightcolorbase[1] * rsurface_entity->colormap_shirtcolor[1];
2275 lightcolorshirt[2] = lightcolorbase[2] * rsurface_entity->colormap_shirtcolor[2];
2278 VectorClear(lightcolorshirt);
2279 switch (r_shadow_rendermode)
2281 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2282 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2283 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2285 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2286 R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2288 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2289 R_Shadow_RenderLighting_Light_Dot3(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2291 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2292 R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2295 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2301 switch (r_shadow_rendermode)
2303 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2304 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2305 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2307 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2308 R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2310 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2311 R_Shadow_RenderLighting_Light_Dot3(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2313 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2314 R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2317 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2323 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)
2325 matrix4x4_t tempmatrix = *matrix;
2326 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2328 // if this light has been compiled before, free the associated data
2329 R_RTLight_Uncompile(rtlight);
2331 // clear it completely to avoid any lingering data
2332 memset(rtlight, 0, sizeof(*rtlight));
2334 // copy the properties
2335 rtlight->matrix_lighttoworld = tempmatrix;
2336 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2337 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2338 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2339 VectorCopy(color, rtlight->color);
2340 rtlight->cubemapname[0] = 0;
2341 if (cubemapname && cubemapname[0])
2342 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2343 rtlight->shadow = shadow;
2344 rtlight->corona = corona;
2345 rtlight->style = style;
2346 rtlight->isstatic = isstatic;
2347 rtlight->coronasizescale = coronasizescale;
2348 rtlight->ambientscale = ambientscale;
2349 rtlight->diffusescale = diffusescale;
2350 rtlight->specularscale = specularscale;
2351 rtlight->flags = flags;
2353 // compute derived data
2354 //rtlight->cullradius = rtlight->radius;
2355 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2356 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2357 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2358 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2359 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2360 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2361 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2364 // compiles rtlight geometry
2365 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2366 void R_RTLight_Compile(rtlight_t *rtlight)
2369 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2370 int lighttris, shadowtris, shadowmeshes, shadowmeshtris;
2371 entity_render_t *ent = r_refdef.worldentity;
2372 model_t *model = r_refdef.worldmodel;
2373 unsigned char *data;
2375 // compile the light
2376 rtlight->compiled = true;
2377 rtlight->static_numleafs = 0;
2378 rtlight->static_numleafpvsbytes = 0;
2379 rtlight->static_leaflist = NULL;
2380 rtlight->static_leafpvs = NULL;
2381 rtlight->static_numsurfaces = 0;
2382 rtlight->static_surfacelist = NULL;
2383 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2384 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2385 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2386 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2387 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2388 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2390 if (model && model->GetLightInfo)
2392 // this variable must be set for the CompileShadowVolume code
2393 r_shadow_compilingrtlight = rtlight;
2394 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);
2395 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);
2396 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2397 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2398 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2399 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2400 rtlight->static_numsurfaces = numsurfaces;
2401 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2402 rtlight->static_numleafs = numleafs;
2403 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2404 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2405 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2406 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2407 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2408 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2409 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2410 if (rtlight->static_numsurfaces)
2411 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2412 if (rtlight->static_numleafs)
2413 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2414 if (rtlight->static_numleafpvsbytes)
2415 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2416 if (rtlight->static_numshadowtrispvsbytes)
2417 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2418 if (rtlight->static_numlighttrispvsbytes)
2419 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2420 if (model->CompileShadowVolume && rtlight->shadow)
2421 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2422 // now we're done compiling the rtlight
2423 r_shadow_compilingrtlight = NULL;
2427 // use smallest available cullradius - box radius or light radius
2428 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2429 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2433 if (rtlight->static_meshchain_shadow)
2436 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2439 shadowmeshtris += mesh->numtriangles;
2444 if (rtlight->static_numlighttrispvsbytes)
2445 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2446 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2450 if (rtlight->static_numlighttrispvsbytes)
2451 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2452 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2455 if (developer.integer >= 10)
2456 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);
2459 void R_RTLight_Uncompile(rtlight_t *rtlight)
2461 if (rtlight->compiled)
2463 if (rtlight->static_meshchain_shadow)
2464 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2465 rtlight->static_meshchain_shadow = NULL;
2466 // these allocations are grouped
2467 if (rtlight->static_surfacelist)
2468 Mem_Free(rtlight->static_surfacelist);
2469 rtlight->static_numleafs = 0;
2470 rtlight->static_numleafpvsbytes = 0;
2471 rtlight->static_leaflist = NULL;
2472 rtlight->static_leafpvs = NULL;
2473 rtlight->static_numsurfaces = 0;
2474 rtlight->static_surfacelist = NULL;
2475 rtlight->static_numshadowtrispvsbytes = 0;
2476 rtlight->static_shadowtrispvs = NULL;
2477 rtlight->static_numlighttrispvsbytes = 0;
2478 rtlight->static_lighttrispvs = NULL;
2479 rtlight->compiled = false;
2483 void R_Shadow_UncompileWorldLights(void)
2486 for (light = r_shadow_worldlightchain;light;light = light->next)
2487 R_RTLight_Uncompile(&light->rtlight);
2490 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2494 // reset the count of frustum planes
2495 // see r_shadow_rtlight_frustumplanes definition for how much this array
2497 r_shadow_rtlight_numfrustumplanes = 0;
2500 // generate a deformed frustum that includes the light origin, this is
2501 // used to cull shadow casting surfaces that can not possibly cast a
2502 // shadow onto the visible light-receiving surfaces, which can be a
2505 // if the light origin is onscreen the result will be 4 planes exactly
2506 // if the light origin is offscreen on only one axis the result will
2507 // be exactly 5 planes (split-side case)
2508 // if the light origin is offscreen on two axes the result will be
2509 // exactly 4 planes (stretched corner case)
2510 for (i = 0;i < 4;i++)
2512 // quickly reject standard frustum planes that put the light
2513 // origin outside the frustum
2514 if (PlaneDiff(rtlight->shadoworigin, &r_view.frustum[i]) < -0.03125)
2517 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = r_view.frustum[i];
2519 // if all the standard frustum planes were accepted, the light is onscreen
2520 // otherwise we need to generate some more planes below...
2521 if (r_shadow_rtlight_numfrustumplanes < 4)
2523 // at least one of the stock frustum planes failed, so we need to
2524 // create one or two custom planes to enclose the light origin
2525 for (i = 0;i < 4;i++)
2527 // create a plane using the view origin and light origin, and a
2528 // single point from the frustum corner set
2529 TriangleNormal(r_view.origin, r_view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2530 VectorNormalize(plane.normal);
2531 plane.dist = DotProduct(r_view.origin, plane.normal);
2532 // see if this plane is backwards and flip it if so
2533 for (j = 0;j < 4;j++)
2534 if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2538 VectorNegate(plane.normal, plane.normal);
2540 // flipped plane, test again to see if it is now valid
2541 for (j = 0;j < 4;j++)
2542 if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2544 // if the plane is still not valid, then it is dividing the
2545 // frustum and has to be rejected
2549 // we have created a valid plane, compute extra info
2550 PlaneClassify(&plane);
2552 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = plane;
2554 // if we've found 5 frustum planes then we have constructed a
2555 // proper split-side case and do not need to keep searching for
2556 // planes to enclose the light origin
2557 if (r_shadow_rtlight_numfrustumplanes == 5)
2565 for (i = 0;i < r_shadow_rtlight_numfrustumplanes;i++)
2567 plane = r_shadow_rtlight_frustumplanes[i];
2568 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));
2573 // now add the light-space box planes if the light box is rotated, as any
2574 // caster outside the oriented light box is irrelevant (even if it passed
2575 // the worldspace light box, which is axial)
2576 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
2578 for (i = 0;i < 6;i++)
2582 v[i >> 1] = (i & 1) ? -1 : 1;
2583 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
2584 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
2585 plane.dist = VectorNormalizeLength(plane.normal);
2586 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
2587 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = plane;
2593 // add the world-space reduced box planes
2594 for (i = 0;i < 6;i++)
2596 VectorClear(plane.normal);
2597 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
2598 plane.dist = (i & 1) ? -r_shadow_rtlight_cullmaxs[i >> 1] : r_shadow_rtlight_cullmins[i >> 1];
2599 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = plane;
2608 // reduce all plane distances to tightly fit the rtlight cull box, which
2610 VectorSet(points[0], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmins[2]);
2611 VectorSet(points[1], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmins[2]);
2612 VectorSet(points[2], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmins[2]);
2613 VectorSet(points[3], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmins[2]);
2614 VectorSet(points[4], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmaxs[2]);
2615 VectorSet(points[5], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmaxs[2]);
2616 VectorSet(points[6], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmaxs[2]);
2617 VectorSet(points[7], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmaxs[2]);
2618 oldnum = r_shadow_rtlight_numfrustumplanes;
2619 r_shadow_rtlight_numfrustumplanes = 0;
2620 for (j = 0;j < oldnum;j++)
2622 // find the nearest point on the box to this plane
2623 bestdist = DotProduct(r_shadow_rtlight_frustumplanes[j].normal, points[0]);
2624 for (i = 1;i < 8;i++)
2626 dist = DotProduct(r_shadow_rtlight_frustumplanes[j].normal, points[i]);
2627 if (bestdist > dist)
2630 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);
2631 // if the nearest point is near or behind the plane, we want this
2632 // plane, otherwise the plane is useless as it won't cull anything
2633 if (r_shadow_rtlight_frustumplanes[j].dist < bestdist + 0.03125)
2635 PlaneClassify(&r_shadow_rtlight_frustumplanes[j]);
2636 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = r_shadow_rtlight_frustumplanes[j];
2643 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2645 RSurf_ActiveWorldEntity();
2646 if (r_shadow_rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2650 for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2652 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2653 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
2654 GL_LockArrays(0, mesh->numverts);
2655 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2657 // decrement stencil if backface is behind depthbuffer
2658 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
2659 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2660 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2661 // increment stencil if frontface is behind depthbuffer
2662 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2663 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2665 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2666 GL_LockArrays(0, 0);
2670 else if (numsurfaces && r_refdef.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
2673 int surfacelistindex;
2674 msurface_t *surface;
2675 R_Shadow_PrepareShadowMark(r_refdef.worldmodel->brush.shadowmesh->numtriangles);
2676 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2678 surface = r_refdef.worldmodel->data_surfaces + surfacelist[surfacelistindex];
2679 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
2680 if (CHECKPVSBIT(trispvs, t))
2681 shadowmarklist[numshadowmark++] = t;
2683 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);
2685 else if (numsurfaces)
2686 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);
2689 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
2691 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2692 vec_t relativeshadowradius;
2693 RSurf_ActiveModelEntity(ent, false, false);
2694 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, relativeshadoworigin);
2695 relativeshadowradius = r_shadow_rtlight->radius / ent->scale;
2696 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2697 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2698 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2699 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2700 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2701 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2702 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2705 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2707 // set up properties for rendering light onto this entity
2708 RSurf_ActiveModelEntity(ent, true, true);
2709 Matrix4x4_Concat(&r_shadow_entitytolight, &r_shadow_rtlight->matrix_worldtolight, &ent->matrix);
2710 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2711 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2712 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2713 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2714 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2717 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2719 if (!r_refdef.worldmodel->DrawLight)
2722 // set up properties for rendering light onto this entity
2723 RSurf_ActiveWorldEntity();
2724 r_shadow_entitytolight = r_shadow_rtlight->matrix_worldtolight;
2725 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2726 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2727 VectorCopy(r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2728 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2729 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2731 r_refdef.worldmodel->DrawLight(r_refdef.worldentity, numsurfaces, surfacelist, trispvs);
2734 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2736 model_t *model = ent->model;
2737 if (!model->DrawLight)
2740 R_Shadow_SetupEntityLight(ent);
2742 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist, NULL);
2745 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2749 int numleafs, numsurfaces;
2750 int *leaflist, *surfacelist;
2751 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
2752 int numlightentities;
2753 int numshadowentities;
2754 entity_render_t *lightentities[MAX_EDICTS];
2755 entity_render_t *shadowentities[MAX_EDICTS];
2757 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2758 // skip lights that are basically invisible (color 0 0 0)
2759 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2762 // loading is done before visibility checks because loading should happen
2763 // all at once at the start of a level, not when it stalls gameplay.
2764 // (especially important to benchmarks)
2766 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2767 R_RTLight_Compile(rtlight);
2769 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2771 // look up the light style value at this time
2772 f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2773 VectorScale(rtlight->color, f, rtlight->currentcolor);
2775 if (rtlight->selected)
2777 f = 2 + sin(realtime * M_PI * 4.0);
2778 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2782 // if lightstyle is currently off, don't draw the light
2783 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2786 // if the light box is offscreen, skip it
2787 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2790 VectorCopy(rtlight->cullmins, r_shadow_rtlight_cullmins);
2791 VectorCopy(rtlight->cullmaxs, r_shadow_rtlight_cullmaxs);
2793 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2795 // compiled light, world available and can receive realtime lighting
2796 // retrieve leaf information
2797 numleafs = rtlight->static_numleafs;
2798 leaflist = rtlight->static_leaflist;
2799 leafpvs = rtlight->static_leafpvs;
2800 numsurfaces = rtlight->static_numsurfaces;
2801 surfacelist = rtlight->static_surfacelist;
2802 shadowtrispvs = rtlight->static_shadowtrispvs;
2803 lighttrispvs = rtlight->static_lighttrispvs;
2805 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2807 // dynamic light, world available and can receive realtime lighting
2808 // calculate lit surfaces and leafs
2809 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);
2810 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);
2811 leaflist = r_shadow_buffer_leaflist;
2812 leafpvs = r_shadow_buffer_leafpvs;
2813 surfacelist = r_shadow_buffer_surfacelist;
2814 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
2815 lighttrispvs = r_shadow_buffer_lighttrispvs;
2816 // if the reduced leaf bounds are offscreen, skip it
2817 if (R_CullBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2828 shadowtrispvs = NULL;
2829 lighttrispvs = NULL;
2831 // check if light is illuminating any visible leafs
2834 for (i = 0;i < numleafs;i++)
2835 if (r_viewcache.world_leafvisible[leaflist[i]])
2840 // set up a scissor rectangle for this light
2841 if (R_Shadow_ScissorForBBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2844 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
2846 // make a list of lit entities and shadow casting entities
2847 numlightentities = 0;
2848 numshadowentities = 0;
2849 // add dynamic entities that are lit by the light
2850 if (r_drawentities.integer)
2852 for (i = 0;i < r_refdef.numentities;i++)
2855 entity_render_t *ent = r_refdef.entities[i];
2857 if (!BoxesOverlap(ent->mins, ent->maxs, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2859 // skip the object entirely if it is not within the valid
2860 // shadow-casting region (which includes the lit region)
2861 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, r_shadow_rtlight_numfrustumplanes, r_shadow_rtlight_frustumplanes))
2863 if (!(model = ent->model))
2865 if (r_viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
2867 // this entity wants to receive light, is visible, and is
2868 // inside the light box
2869 // TODO: check if the surfaces in the model can receive light
2870 // so now check if it's in a leaf seen by the light
2871 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2873 lightentities[numlightentities++] = ent;
2874 // since it is lit, it probably also casts a shadow...
2875 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2876 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2877 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2878 shadowentities[numshadowentities++] = ent;
2880 else if (ent->flags & RENDER_SHADOW)
2882 // this entity is not receiving light, but may still need to
2884 // TODO: check if the surfaces in the model can cast shadow
2885 // now check if it is in a leaf seen by the light
2886 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2888 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2889 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2890 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2891 shadowentities[numshadowentities++] = ent;
2896 // return if there's nothing at all to light
2897 if (!numlightentities && !numsurfaces)
2900 // don't let sound skip if going slow
2901 if (r_refdef.extraupdate)
2904 // make this the active rtlight for rendering purposes
2905 R_Shadow_RenderMode_ActiveLight(rtlight);
2906 // count this light in the r_speeds
2907 r_refdef.stats.lights++;
2910 if (numsurfaces + numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2912 // draw stencil shadow volumes to mask off pixels that are in shadow
2913 // so that they won't receive lighting
2917 R_Shadow_RenderMode_StencilShadowVolumes();
2919 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
2920 for (i = 0;i < numshadowentities;i++)
2921 R_Shadow_DrawEntityShadow(shadowentities[i]);
2924 // optionally draw visible shape of the shadow volumes
2925 // for performance analysis by level designers
2926 if (r_showshadowvolumes.integer)
2928 R_Shadow_RenderMode_VisibleShadowVolumes();
2930 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
2931 for (i = 0;i < numshadowentities;i++)
2932 R_Shadow_DrawEntityShadow(shadowentities[i]);
2936 if (numsurfaces + numlightentities)
2938 // draw lighting in the unmasked areas
2939 R_Shadow_RenderMode_Lighting(usestencil, false);
2941 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
2942 for (i = 0;i < numlightentities;i++)
2943 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2945 // optionally draw the illuminated areas
2946 // for performance analysis by level designers
2947 if (r_showlighting.integer)
2949 R_Shadow_RenderMode_VisibleLighting(usestencil && !r_showdisabledepthtest.integer, false);
2951 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
2952 for (i = 0;i < numlightentities;i++)
2953 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2958 void R_Shadow_DrawLightSprites(void);
2959 void R_ShadowVolumeLighting(qboolean visible)
2964 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2965 R_Shadow_EditLights_Reload_f();
2967 if (r_editlights.integer)
2968 R_Shadow_DrawLightSprites();
2970 R_Shadow_RenderMode_Begin();
2972 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2973 if (r_shadow_debuglight.integer >= 0)
2975 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2976 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2977 R_DrawRTLight(&light->rtlight, visible);
2980 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2981 if (light->flags & flag)
2982 R_DrawRTLight(&light->rtlight, visible);
2983 if (r_refdef.rtdlight)
2984 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
2985 R_DrawRTLight(&r_refdef.lights[lnum], visible);
2987 R_Shadow_RenderMode_End();
2990 extern void R_SetupView(const matrix4x4_t *matrix);
2991 extern cvar_t r_shadows_throwdistance;
2992 void R_DrawModelShadows(void)
2995 float relativethrowdistance;
2996 entity_render_t *ent;
2997 vec3_t relativelightorigin;
2998 vec3_t relativelightdirection;
2999 vec3_t relativeshadowmins, relativeshadowmaxs;
3002 if (!r_drawentities.integer || !gl_stencil)
3006 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
3008 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3010 if (gl_ext_separatestencil.integer)
3011 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
3012 else if (gl_ext_stenciltwoside.integer)
3013 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
3015 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
3017 R_Shadow_RenderMode_StencilShadowVolumes();
3019 for (i = 0;i < r_refdef.numentities;i++)
3021 ent = r_refdef.entities[i];
3022 // cast shadows from anything that is not a submodel of the map
3023 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
3025 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3026 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3027 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3028 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3029 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3030 RSurf_ActiveModelEntity(ent, false, false);
3031 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
3035 // not really the right mode, but this will disable any silly stencil features
3036 R_Shadow_RenderMode_VisibleLighting(true, true);
3038 // vertex coordinates for a quad that covers the screen exactly
3039 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
3040 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
3041 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
3042 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
3044 // set up ortho view for rendering this pass
3045 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
3046 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
3047 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
3048 GL_ScissorTest(true);
3049 R_Mesh_Matrix(&identitymatrix);
3050 R_Mesh_ResetTextureState();
3051 R_Mesh_VertexPointer(vertex3f, 0, 0);
3052 R_Mesh_ColorPointer(NULL, 0, 0);
3054 // set up a 50% darkening blend on shadowed areas
3055 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3056 GL_DepthTest(false);
3057 GL_DepthMask(false);
3058 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
3059 GL_Color(0, 0, 0, 0.5);
3060 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
3061 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
3062 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
3063 qglStencilMask(~0);CHECKGLERROR
3064 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3065 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
3067 // apply the blend to the shadowed areas
3068 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3070 // restoring the perspective view is done by R_RenderScene
3071 //R_SetupView(&r_view.matrix);
3073 // restore other state to normal
3074 R_Shadow_RenderMode_End();
3078 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3079 typedef struct suffixinfo_s
3082 qboolean flipx, flipy, flipdiagonal;
3085 static suffixinfo_t suffix[3][6] =
3088 {"px", false, false, false},
3089 {"nx", false, false, false},
3090 {"py", false, false, false},
3091 {"ny", false, false, false},
3092 {"pz", false, false, false},
3093 {"nz", false, false, false}
3096 {"posx", false, false, false},
3097 {"negx", false, false, false},
3098 {"posy", false, false, false},
3099 {"negy", false, false, false},
3100 {"posz", false, false, false},
3101 {"negz", false, false, false}
3104 {"rt", true, false, true},
3105 {"lf", false, true, true},
3106 {"ft", true, true, false},
3107 {"bk", false, false, false},
3108 {"up", true, false, true},
3109 {"dn", true, false, true}
3113 static int componentorder[4] = {0, 1, 2, 3};
3115 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3117 int i, j, cubemapsize;
3118 unsigned char *cubemappixels, *image_rgba;
3119 rtexture_t *cubemaptexture;
3121 // must start 0 so the first loadimagepixels has no requested width/height
3123 cubemappixels = NULL;
3124 cubemaptexture = NULL;
3125 // keep trying different suffix groups (posx, px, rt) until one loads
3126 for (j = 0;j < 3 && !cubemappixels;j++)
3128 // load the 6 images in the suffix group
3129 for (i = 0;i < 6;i++)
3131 // generate an image name based on the base and and suffix
3132 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3134 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
3136 // an image loaded, make sure width and height are equal
3137 if (image_width == image_height)
3139 // if this is the first image to load successfully, allocate the cubemap memory
3140 if (!cubemappixels && image_width >= 1)
3142 cubemapsize = image_width;
3143 // note this clears to black, so unavailable sides are black
3144 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3146 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3148 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);
3151 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3153 Mem_Free(image_rgba);
3157 // if a cubemap loaded, upload it
3160 if (!r_shadow_filters_texturepool)
3161 r_shadow_filters_texturepool = R_AllocTexturePool();
3162 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
3163 Mem_Free(cubemappixels);
3167 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3168 for (j = 0;j < 3;j++)
3169 for (i = 0;i < 6;i++)
3170 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3171 Con_Print(" and was unable to find any of them.\n");
3173 return cubemaptexture;
3176 rtexture_t *R_Shadow_Cubemap(const char *basename)
3179 for (i = 0;i < numcubemaps;i++)
3180 if (!strcasecmp(cubemaps[i].basename, basename))
3181 return cubemaps[i].texture;
3182 if (i >= MAX_CUBEMAPS)
3183 return r_texture_whitecube;
3185 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
3186 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3187 if (!cubemaps[i].texture)
3188 cubemaps[i].texture = r_texture_whitecube;
3189 return cubemaps[i].texture;
3192 void R_Shadow_FreeCubemaps(void)
3195 R_FreeTexturePool(&r_shadow_filters_texturepool);
3198 dlight_t *R_Shadow_NewWorldLight(void)
3201 light = (dlight_t *)Mem_Alloc(r_main_mempool, sizeof(dlight_t));
3202 light->next = r_shadow_worldlightchain;
3203 r_shadow_worldlightchain = light;
3207 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)
3210 // validate parameters
3211 if (style < 0 || style >= MAX_LIGHTSTYLES)
3213 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3219 // copy to light properties
3220 VectorCopy(origin, light->origin);
3221 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3222 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3223 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3224 light->color[0] = max(color[0], 0);
3225 light->color[1] = max(color[1], 0);
3226 light->color[2] = max(color[2], 0);
3227 light->radius = max(radius, 0);
3228 light->style = style;
3229 light->shadow = shadowenable;
3230 light->corona = corona;
3231 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3232 light->coronasizescale = coronasizescale;
3233 light->ambientscale = ambientscale;
3234 light->diffusescale = diffusescale;
3235 light->specularscale = specularscale;
3236 light->flags = flags;
3238 // update renderable light data
3239 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
3240 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);
3243 void R_Shadow_FreeWorldLight(dlight_t *light)
3245 dlight_t **lightpointer;
3246 R_RTLight_Uncompile(&light->rtlight);
3247 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3248 if (*lightpointer != light)
3249 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
3250 *lightpointer = light->next;
3254 void R_Shadow_ClearWorldLights(void)
3256 while (r_shadow_worldlightchain)
3257 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3258 r_shadow_selectedlight = NULL;
3259 R_Shadow_FreeCubemaps();
3262 void R_Shadow_SelectLight(dlight_t *light)
3264 if (r_shadow_selectedlight)
3265 r_shadow_selectedlight->selected = false;
3266 r_shadow_selectedlight = light;
3267 if (r_shadow_selectedlight)
3268 r_shadow_selectedlight->selected = true;
3271 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3273 // this is never batched (there can be only one)
3274 float scale = r_editlights_cursorgrid.value * 0.5f;
3275 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);
3278 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3280 // this is never batched (due to the ent parameter changing every time)
3281 // so numsurfaces == 1 and surfacelist[0] == lightnumber
3283 const dlight_t *light = (dlight_t *)ent;
3285 if (light->selected)
3286 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3289 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);
3292 void R_Shadow_DrawLightSprites(void)
3297 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3298 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 1+(i % 5), &light->rtlight);
3299 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
3302 void R_Shadow_SelectLightInView(void)
3304 float bestrating, rating, temp[3];
3305 dlight_t *best, *light;
3308 for (light = r_shadow_worldlightchain;light;light = light->next)
3310 VectorSubtract(light->origin, r_view.origin, temp);
3311 rating = (DotProduct(temp, r_view.forward) / sqrt(DotProduct(temp, temp)));
3314 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3315 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)
3317 bestrating = rating;
3322 R_Shadow_SelectLight(best);
3325 void R_Shadow_LoadWorldLights(void)
3327 int n, a, style, shadow, flags;
3328 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3329 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3330 if (r_refdef.worldmodel == NULL)
3332 Con_Print("No map loaded.\n");
3335 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3336 strlcat (name, ".rtlights", sizeof (name));
3337 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3347 for (;COM_Parse(t, true) && strcmp(
3348 if (COM_Parse(t, true))
3350 if (com_token[0] == '!')
3353 origin[0] = atof(com_token+1);
3356 origin[0] = atof(com_token);
3361 while (*s && *s != '\n' && *s != '\r')
3367 // check for modifier flags
3374 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);
3377 flags = LIGHTFLAG_REALTIMEMODE;
3385 coronasizescale = 0.25f;
3387 VectorClear(angles);
3390 if (a < 9 || !strcmp(cubemapname, "\"\""))
3392 // remove quotes on cubemapname
3393 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3396 namelen = strlen(cubemapname) - 2;
3397 memmove(cubemapname, cubemapname + 1, namelen);
3398 cubemapname[namelen] = '\0';
3402 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);
3405 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3413 Con_Printf("invalid rtlights file \"%s\"\n", name);
3414 Mem_Free(lightsstring);
3418 void R_Shadow_SaveWorldLights(void)
3421 size_t bufchars, bufmaxchars;
3423 char name[MAX_QPATH];
3424 char line[MAX_INPUTLINE];
3425 if (!r_shadow_worldlightchain)
3427 if (r_refdef.worldmodel == NULL)
3429 Con_Print("No map loaded.\n");
3432 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3433 strlcat (name, ".rtlights", sizeof (name));
3434 bufchars = bufmaxchars = 0;
3436 for (light = r_shadow_worldlightchain;light;light = light->next)
3438 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3439 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);
3440 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3441 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]);
3443 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);
3444 if (bufchars + strlen(line) > bufmaxchars)
3446 bufmaxchars = bufchars + strlen(line) + 2048;
3448 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3452 memcpy(buf, oldbuf, bufchars);
3458 memcpy(buf + bufchars, line, strlen(line));
3459 bufchars += strlen(line);
3463 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3468 void R_Shadow_LoadLightsFile(void)
3471 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3472 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3473 if (r_refdef.worldmodel == NULL)
3475 Con_Print("No map loaded.\n");
3478 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3479 strlcat (name, ".lights", sizeof (name));
3480 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3488 while (*s && *s != '\n' && *s != '\r')
3494 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);
3498 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);
3501 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3502 radius = bound(15, radius, 4096);
3503 VectorScale(color, (2.0f / (8388608.0f)), color);
3504 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3512 Con_Printf("invalid lights file \"%s\"\n", name);
3513 Mem_Free(lightsstring);
3517 // tyrlite/hmap2 light types in the delay field
3518 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3520 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3522 int entnum, style, islight, skin, pflags, effects, type, n;
3525 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3526 char key[256], value[MAX_INPUTLINE];
3528 if (r_refdef.worldmodel == NULL)
3530 Con_Print("No map loaded.\n");
3533 // try to load a .ent file first
3534 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3535 strlcat (key, ".ent", sizeof (key));
3536 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3537 // and if that is not found, fall back to the bsp file entity string
3539 data = r_refdef.worldmodel->brush.entities;
3542 for (entnum = 0;COM_ParseTokenConsole(&data) && com_token[0] == '{';entnum++)
3544 type = LIGHTTYPE_MINUSX;
3545 origin[0] = origin[1] = origin[2] = 0;
3546 originhack[0] = originhack[1] = originhack[2] = 0;
3547 angles[0] = angles[1] = angles[2] = 0;
3548 color[0] = color[1] = color[2] = 1;
3549 light[0] = light[1] = light[2] = 1;light[3] = 300;
3550 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3560 if (!COM_ParseTokenConsole(&data))
3562 if (com_token[0] == '}')
3563 break; // end of entity
3564 if (com_token[0] == '_')
3565 strlcpy(key, com_token + 1, sizeof(key));
3567 strlcpy(key, com_token, sizeof(key));
3568 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3569 key[strlen(key)-1] = 0;
3570 if (!COM_ParseTokenConsole(&data))
3572 strlcpy(value, com_token, sizeof(value));
3574 // now that we have the key pair worked out...
3575 if (!strcmp("light", key))
3577 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3581 light[0] = vec[0] * (1.0f / 256.0f);
3582 light[1] = vec[0] * (1.0f / 256.0f);
3583 light[2] = vec[0] * (1.0f / 256.0f);
3589 light[0] = vec[0] * (1.0f / 255.0f);
3590 light[1] = vec[1] * (1.0f / 255.0f);
3591 light[2] = vec[2] * (1.0f / 255.0f);
3595 else if (!strcmp("delay", key))
3597 else if (!strcmp("origin", key))
3598 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3599 else if (!strcmp("angle", key))
3600 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3601 else if (!strcmp("angles", key))
3602 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3603 else if (!strcmp("color", key))
3604 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3605 else if (!strcmp("wait", key))
3606 fadescale = atof(value);
3607 else if (!strcmp("classname", key))
3609 if (!strncmp(value, "light", 5))
3612 if (!strcmp(value, "light_fluoro"))
3617 overridecolor[0] = 1;
3618 overridecolor[1] = 1;
3619 overridecolor[2] = 1;
3621 if (!strcmp(value, "light_fluorospark"))
3626 overridecolor[0] = 1;
3627 overridecolor[1] = 1;
3628 overridecolor[2] = 1;
3630 if (!strcmp(value, "light_globe"))
3635 overridecolor[0] = 1;
3636 overridecolor[1] = 0.8;
3637 overridecolor[2] = 0.4;
3639 if (!strcmp(value, "light_flame_large_yellow"))
3644 overridecolor[0] = 1;
3645 overridecolor[1] = 0.5;
3646 overridecolor[2] = 0.1;
3648 if (!strcmp(value, "light_flame_small_yellow"))
3653 overridecolor[0] = 1;
3654 overridecolor[1] = 0.5;
3655 overridecolor[2] = 0.1;
3657 if (!strcmp(value, "light_torch_small_white"))
3662 overridecolor[0] = 1;
3663 overridecolor[1] = 0.5;
3664 overridecolor[2] = 0.1;
3666 if (!strcmp(value, "light_torch_small_walltorch"))
3671 overridecolor[0] = 1;
3672 overridecolor[1] = 0.5;
3673 overridecolor[2] = 0.1;
3677 else if (!strcmp("style", key))
3678 style = atoi(value);
3679 else if (!strcmp("skin", key))
3680 skin = (int)atof(value);
3681 else if (!strcmp("pflags", key))
3682 pflags = (int)atof(value);
3683 else if (!strcmp("effects", key))
3684 effects = (int)atof(value);
3685 else if (r_refdef.worldmodel->type == mod_brushq3)
3687 if (!strcmp("scale", key))
3688 lightscale = atof(value);
3689 if (!strcmp("fade", key))
3690 fadescale = atof(value);
3695 if (lightscale <= 0)
3699 if (color[0] == color[1] && color[0] == color[2])
3701 color[0] *= overridecolor[0];
3702 color[1] *= overridecolor[1];
3703 color[2] *= overridecolor[2];
3705 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3706 color[0] = color[0] * light[0];
3707 color[1] = color[1] * light[1];
3708 color[2] = color[2] * light[2];
3711 case LIGHTTYPE_MINUSX:
3713 case LIGHTTYPE_RECIPX:
3715 VectorScale(color, (1.0f / 16.0f), color);
3717 case LIGHTTYPE_RECIPXX:
3719 VectorScale(color, (1.0f / 16.0f), color);
3722 case LIGHTTYPE_NONE:
3726 case LIGHTTYPE_MINUSXX:
3729 VectorAdd(origin, originhack, origin);
3731 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);
3734 Mem_Free(entfiledata);
3738 void R_Shadow_SetCursorLocationForView(void)
3741 vec3_t dest, endpos;
3743 VectorMA(r_view.origin, r_editlights_cursordistance.value, r_view.forward, dest);
3744 trace = CL_Move(r_view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
3745 if (trace.fraction < 1)
3747 dist = trace.fraction * r_editlights_cursordistance.value;
3748 push = r_editlights_cursorpushback.value;
3752 VectorMA(trace.endpos, push, r_view.forward, endpos);
3753 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3757 VectorClear( endpos );
3759 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3760 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3761 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3764 void R_Shadow_UpdateWorldLightSelection(void)
3766 if (r_editlights.integer)
3768 R_Shadow_SetCursorLocationForView();
3769 R_Shadow_SelectLightInView();
3772 R_Shadow_SelectLight(NULL);
3775 void R_Shadow_EditLights_Clear_f(void)
3777 R_Shadow_ClearWorldLights();
3780 void R_Shadow_EditLights_Reload_f(void)
3782 if (!r_refdef.worldmodel)
3784 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3785 R_Shadow_ClearWorldLights();
3786 R_Shadow_LoadWorldLights();
3787 if (r_shadow_worldlightchain == NULL)
3789 R_Shadow_LoadLightsFile();
3790 if (r_shadow_worldlightchain == NULL)
3791 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3795 void R_Shadow_EditLights_Save_f(void)
3797 if (!r_refdef.worldmodel)
3799 R_Shadow_SaveWorldLights();
3802 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3804 R_Shadow_ClearWorldLights();
3805 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3808 void R_Shadow_EditLights_ImportLightsFile_f(void)
3810 R_Shadow_ClearWorldLights();
3811 R_Shadow_LoadLightsFile();
3814 void R_Shadow_EditLights_Spawn_f(void)
3817 if (!r_editlights.integer)
3819 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3822 if (Cmd_Argc() != 1)
3824 Con_Print("r_editlights_spawn does not take parameters\n");
3827 color[0] = color[1] = color[2] = 1;
3828 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3831 void R_Shadow_EditLights_Edit_f(void)
3833 vec3_t origin, angles, color;
3834 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3835 int style, shadows, flags, normalmode, realtimemode;
3836 char cubemapname[MAX_INPUTLINE];
3837 if (!r_editlights.integer)
3839 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3842 if (!r_shadow_selectedlight)
3844 Con_Print("No selected light.\n");
3847 VectorCopy(r_shadow_selectedlight->origin, origin);
3848 VectorCopy(r_shadow_selectedlight->angles, angles);
3849 VectorCopy(r_shadow_selectedlight->color, color);
3850 radius = r_shadow_selectedlight->radius;
3851 style = r_shadow_selectedlight->style;
3852 if (r_shadow_selectedlight->cubemapname)
3853 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3856 shadows = r_shadow_selectedlight->shadow;
3857 corona = r_shadow_selectedlight->corona;
3858 coronasizescale = r_shadow_selectedlight->coronasizescale;
3859 ambientscale = r_shadow_selectedlight->ambientscale;
3860 diffusescale = r_shadow_selectedlight->diffusescale;
3861 specularscale = r_shadow_selectedlight->specularscale;
3862 flags = r_shadow_selectedlight->flags;
3863 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3864 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3865 if (!strcmp(Cmd_Argv(1), "origin"))
3867 if (Cmd_Argc() != 5)
3869 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3872 origin[0] = atof(Cmd_Argv(2));
3873 origin[1] = atof(Cmd_Argv(3));
3874 origin[2] = atof(Cmd_Argv(4));
3876 else if (!strcmp(Cmd_Argv(1), "originx"))
3878 if (Cmd_Argc() != 3)
3880 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3883 origin[0] = atof(Cmd_Argv(2));
3885 else if (!strcmp(Cmd_Argv(1), "originy"))
3887 if (Cmd_Argc() != 3)
3889 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3892 origin[1] = atof(Cmd_Argv(2));
3894 else if (!strcmp(Cmd_Argv(1), "originz"))
3896 if (Cmd_Argc() != 3)
3898 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3901 origin[2] = atof(Cmd_Argv(2));
3903 else if (!strcmp(Cmd_Argv(1), "move"))
3905 if (Cmd_Argc() != 5)
3907 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3910 origin[0] += atof(Cmd_Argv(2));
3911 origin[1] += atof(Cmd_Argv(3));
3912 origin[2] += atof(Cmd_Argv(4));
3914 else if (!strcmp(Cmd_Argv(1), "movex"))
3916 if (Cmd_Argc() != 3)
3918 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3921 origin[0] += atof(Cmd_Argv(2));
3923 else if (!strcmp(Cmd_Argv(1), "movey"))
3925 if (Cmd_Argc() != 3)
3927 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3930 origin[1] += atof(Cmd_Argv(2));
3932 else if (!strcmp(Cmd_Argv(1), "movez"))
3934 if (Cmd_Argc() != 3)
3936 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3939 origin[2] += atof(Cmd_Argv(2));
3941 else if (!strcmp(Cmd_Argv(1), "angles"))
3943 if (Cmd_Argc() != 5)
3945 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3948 angles[0] = atof(Cmd_Argv(2));
3949 angles[1] = atof(Cmd_Argv(3));
3950 angles[2] = atof(Cmd_Argv(4));
3952 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3954 if (Cmd_Argc() != 3)
3956 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3959 angles[0] = atof(Cmd_Argv(2));
3961 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3963 if (Cmd_Argc() != 3)
3965 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3968 angles[1] = atof(Cmd_Argv(2));
3970 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3972 if (Cmd_Argc() != 3)
3974 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3977 angles[2] = atof(Cmd_Argv(2));
3979 else if (!strcmp(Cmd_Argv(1), "color"))
3981 if (Cmd_Argc() != 5)
3983 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3986 color[0] = atof(Cmd_Argv(2));
3987 color[1] = atof(Cmd_Argv(3));
3988 color[2] = atof(Cmd_Argv(4));
3990 else if (!strcmp(Cmd_Argv(1), "radius"))
3992 if (Cmd_Argc() != 3)
3994 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3997 radius = atof(Cmd_Argv(2));
3999 else if (!strcmp(Cmd_Argv(1), "colorscale"))
4001 if (Cmd_Argc() == 3)
4003 double scale = atof(Cmd_Argv(2));
4010 if (Cmd_Argc() != 5)
4012 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
4015 color[0] *= atof(Cmd_Argv(2));
4016 color[1] *= atof(Cmd_Argv(3));
4017 color[2] *= atof(Cmd_Argv(4));
4020 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
4022 if (Cmd_Argc() != 3)
4024 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4027 radius *= atof(Cmd_Argv(2));
4029 else if (!strcmp(Cmd_Argv(1), "style"))
4031 if (Cmd_Argc() != 3)
4033 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4036 style = atoi(Cmd_Argv(2));
4038 else if (!strcmp(Cmd_Argv(1), "cubemap"))
4042 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4045 if (Cmd_Argc() == 3)
4046 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
4050 else if (!strcmp(Cmd_Argv(1), "shadows"))
4052 if (Cmd_Argc() != 3)
4054 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4057 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4059 else if (!strcmp(Cmd_Argv(1), "corona"))
4061 if (Cmd_Argc() != 3)
4063 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4066 corona = atof(Cmd_Argv(2));
4068 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4070 if (Cmd_Argc() != 3)
4072 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4075 coronasizescale = atof(Cmd_Argv(2));
4077 else if (!strcmp(Cmd_Argv(1), "ambient"))
4079 if (Cmd_Argc() != 3)
4081 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4084 ambientscale = atof(Cmd_Argv(2));
4086 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4088 if (Cmd_Argc() != 3)
4090 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4093 diffusescale = atof(Cmd_Argv(2));
4095 else if (!strcmp(Cmd_Argv(1), "specular"))
4097 if (Cmd_Argc() != 3)
4099 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4102 specularscale = atof(Cmd_Argv(2));
4104 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4106 if (Cmd_Argc() != 3)
4108 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4111 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4113 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4115 if (Cmd_Argc() != 3)
4117 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4120 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4124 Con_Print("usage: r_editlights_edit [property] [value]\n");
4125 Con_Print("Selected light's properties:\n");
4126 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4127 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4128 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4129 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4130 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4131 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4132 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4133 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4134 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4135 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4136 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4137 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4138 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4139 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4142 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4143 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4146 void R_Shadow_EditLights_EditAll_f(void)
4150 if (!r_editlights.integer)
4152 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4156 for (light = r_shadow_worldlightchain;light;light = light->next)
4158 R_Shadow_SelectLight(light);
4159 R_Shadow_EditLights_Edit_f();
4163 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4165 int lightnumber, lightcount;
4169 if (!r_editlights.integer)
4175 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4176 if (light == r_shadow_selectedlight)
4177 lightnumber = lightcount;
4178 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;
4179 if (r_shadow_selectedlight == NULL)
4181 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4182 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;
4183 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;
4184 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;
4185 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4186 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4187 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4188 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;
4189 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4190 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4191 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4192 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4193 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4194 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;
4195 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;
4198 void R_Shadow_EditLights_ToggleShadow_f(void)
4200 if (!r_editlights.integer)
4202 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4205 if (!r_shadow_selectedlight)
4207 Con_Print("No selected light.\n");
4210 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);
4213 void R_Shadow_EditLights_ToggleCorona_f(void)
4215 if (!r_editlights.integer)
4217 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4220 if (!r_shadow_selectedlight)
4222 Con_Print("No selected light.\n");
4225 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);
4228 void R_Shadow_EditLights_Remove_f(void)
4230 if (!r_editlights.integer)
4232 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4235 if (!r_shadow_selectedlight)
4237 Con_Print("No selected light.\n");
4240 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4241 r_shadow_selectedlight = NULL;
4244 void R_Shadow_EditLights_Help_f(void)
4247 "Documentation on r_editlights system:\n"
4249 "r_editlights : enable/disable editing mode\n"
4250 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4251 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4252 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4253 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4254 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4256 "r_editlights_help : this help\n"
4257 "r_editlights_clear : remove all lights\n"
4258 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4259 "r_editlights_save : save to .rtlights file\n"
4260 "r_editlights_spawn : create a light with default settings\n"
4261 "r_editlights_edit command : edit selected light - more documentation below\n"
4262 "r_editlights_remove : remove selected light\n"
4263 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4264 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4265 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4267 "origin x y z : set light location\n"
4268 "originx x: set x component of light location\n"
4269 "originy y: set y component of light location\n"
4270 "originz z: set z component of light location\n"
4271 "move x y z : adjust light location\n"
4272 "movex x: adjust x component of light location\n"
4273 "movey y: adjust y component of light location\n"
4274 "movez z: adjust z component of light location\n"
4275 "angles x y z : set light angles\n"
4276 "anglesx x: set x component of light angles\n"
4277 "anglesy y: set y component of light angles\n"
4278 "anglesz z: set z component of light angles\n"
4279 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4280 "radius radius : set radius (size) of light\n"
4281 "colorscale grey : multiply color of light (1 does nothing)\n"
4282 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4283 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4284 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4285 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4286 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4287 "shadows 1/0 : turn on/off shadows\n"
4288 "corona n : set corona intensity\n"
4289 "coronasize n : set corona size (0-1)\n"
4290 "ambient n : set ambient intensity (0-1)\n"
4291 "diffuse n : set diffuse intensity (0-1)\n"
4292 "specular n : set specular intensity (0-1)\n"
4293 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4294 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4295 "<nothing> : print light properties to console\n"
4299 void R_Shadow_EditLights_CopyInfo_f(void)
4301 if (!r_editlights.integer)
4303 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4306 if (!r_shadow_selectedlight)
4308 Con_Print("No selected light.\n");
4311 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4312 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4313 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4314 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4315 if (r_shadow_selectedlight->cubemapname)
4316 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
4318 r_shadow_bufferlight.cubemapname[0] = 0;
4319 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4320 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4321 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4322 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4323 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4324 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4325 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4328 void R_Shadow_EditLights_PasteInfo_f(void)
4330 if (!r_editlights.integer)
4332 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4335 if (!r_shadow_selectedlight)
4337 Con_Print("No selected light.\n");
4340 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);
4343 void R_Shadow_EditLights_Init(void)
4345 Cvar_RegisterVariable(&r_editlights);
4346 Cvar_RegisterVariable(&r_editlights_cursordistance);
4347 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4348 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4349 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4350 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4351 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
4352 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
4353 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)");
4354 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
4355 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
4356 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
4357 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)");
4358 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
4359 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
4360 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
4361 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
4362 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
4363 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
4364 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)");