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);
1009 GL_DepthRange(0, 1);
1011 GL_DepthMask(false);
1012 GL_Color(0, 0, 0, 1);
1013 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1015 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1017 if (gl_ext_separatestencil.integer)
1018 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
1019 else if (gl_ext_stenciltwoside.integer)
1020 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
1022 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
1024 if (r_glsl.integer && gl_support_fragment_shader)
1025 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1026 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1027 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1029 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1032 void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
1034 r_shadow_rtlight = rtlight;
1037 void R_Shadow_RenderMode_Reset(void)
1040 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1042 qglUseProgramObjectARB(0);CHECKGLERROR
1044 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1046 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1048 R_Mesh_ColorPointer(NULL, 0, 0);
1049 R_Mesh_ResetTextureState();
1050 GL_DepthRange(0, 1);
1052 GL_DepthMask(false);
1053 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1054 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1055 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1056 qglStencilMask(~0);CHECKGLERROR
1057 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1058 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1059 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
1060 GL_Color(1, 1, 1, 1);
1061 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
1062 GL_BlendFunc(GL_ONE, GL_ZERO);
1065 void R_Shadow_RenderMode_StencilShadowVolumes(void)
1068 R_Shadow_RenderMode_Reset();
1069 GL_ColorMask(0, 0, 0, 0);
1070 qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1071 qglDepthFunc(GL_LESS);CHECKGLERROR
1072 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1073 r_shadow_rendermode = r_shadow_shadowingrendermode;
1074 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SEPARATESTENCIL)
1076 GL_CullFace(GL_NONE);
1077 qglStencilOpSeparate(GL_BACK, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR // quake is backwards, this is front faces
1078 qglStencilOpSeparate(GL_FRONT, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR // quake is backwards, this is back faces
1080 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1082 GL_CullFace(GL_NONE);
1083 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1084 qglActiveStencilFaceEXT(GL_BACK);CHECKGLERROR // quake is backwards, this is front faces
1085 qglStencilMask(~0);CHECKGLERROR
1086 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1087 qglActiveStencilFaceEXT(GL_FRONT);CHECKGLERROR // quake is backwards, this is back faces
1088 qglStencilMask(~0);CHECKGLERROR
1089 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1091 GL_Clear(GL_STENCIL_BUFFER_BIT);
1092 r_refdef.stats.lights_clears++;
1095 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
1098 R_Shadow_RenderMode_Reset();
1099 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1102 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1106 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1107 // only draw light where this geometry was already rendered AND the
1108 // stencil is 128 (values other than this mean shadow)
1109 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1111 r_shadow_rendermode = r_shadow_lightingrendermode;
1112 // do global setup needed for the chosen lighting mode
1113 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1115 R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
1116 R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
1117 R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
1118 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_rtlight->currentcubemap)); // light filter
1119 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
1120 R_Mesh_TexBind(5, R_GetTexture(r_texture_white)); // pants
1121 R_Mesh_TexBind(6, R_GetTexture(r_texture_white)); // shirt
1122 R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); // lightmap
1123 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); // deluxemap
1124 R_Mesh_TexBind(9, R_GetTexture(r_texture_black)); // glow
1125 //R_Mesh_TexMatrix(3, r_shadow_entitytolight); // light filter matrix
1126 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1127 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1132 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1135 R_Shadow_RenderMode_Reset();
1136 GL_BlendFunc(GL_ONE, GL_ONE);
1137 GL_DepthRange(0, 1);
1138 GL_DepthTest(r_showshadowvolumes.integer < 2);
1139 GL_Color(0.0, 0.0125 * r_view.colorscale, 0.1 * r_view.colorscale, 1);
1140 qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1141 GL_CullFace(GL_NONE);
1142 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1145 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1148 R_Shadow_RenderMode_Reset();
1149 GL_BlendFunc(GL_ONE, GL_ONE);
1150 GL_DepthRange(0, 1);
1151 GL_DepthTest(r_showlighting.integer < 2);
1152 GL_Color(0.1 * r_view.colorscale, 0.0125 * r_view.colorscale, 0, 1);
1155 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1159 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1160 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1162 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1165 void R_Shadow_RenderMode_End(void)
1168 R_Shadow_RenderMode_Reset();
1169 R_Shadow_RenderMode_ActiveLight(NULL);
1171 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1172 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1175 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1177 int i, ix1, iy1, ix2, iy2;
1178 float x1, y1, x2, y2;
1181 mplane_t planes[11];
1182 float vertex3f[256*3];
1184 // if view is inside the light box, just say yes it's visible
1185 if (BoxesOverlap(r_view.origin, r_view.origin, mins, maxs))
1187 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1191 // create a temporary brush describing the area the light can affect in worldspace
1192 VectorNegate(r_view.frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -r_view.frustum[0].dist;
1193 VectorNegate(r_view.frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -r_view.frustum[1].dist;
1194 VectorNegate(r_view.frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -r_view.frustum[2].dist;
1195 VectorNegate(r_view.frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -r_view.frustum[3].dist;
1196 VectorNegate(r_view.frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -r_view.frustum[4].dist;
1197 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1198 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1199 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1200 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1201 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1202 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1204 // turn the brush into a mesh
1205 memset(&mesh, 0, sizeof(rmesh_t));
1206 mesh.maxvertices = 256;
1207 mesh.vertex3f = vertex3f;
1208 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1209 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1211 // if that mesh is empty, the light is not visible at all
1212 if (!mesh.numvertices)
1215 if (!r_shadow_scissor.integer)
1218 // if that mesh is not empty, check what area of the screen it covers
1219 x1 = y1 = x2 = y2 = 0;
1221 //Con_Printf("%i vertices to transform...\n", mesh.numvertices);
1222 for (i = 0;i < mesh.numvertices;i++)
1224 VectorCopy(mesh.vertex3f + i * 3, v);
1225 GL_TransformToScreen(v, v2);
1226 //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]);
1229 if (x1 > v2[0]) x1 = v2[0];
1230 if (x2 < v2[0]) x2 = v2[0];
1231 if (y1 > v2[1]) y1 = v2[1];
1232 if (y2 < v2[1]) y2 = v2[1];
1241 // now convert the scissor rectangle to integer screen coordinates
1242 ix1 = (int)(x1 - 1.0f);
1243 iy1 = (int)(y1 - 1.0f);
1244 ix2 = (int)(x2 + 1.0f);
1245 iy2 = (int)(y2 + 1.0f);
1246 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1248 // clamp it to the screen
1249 if (ix1 < r_view.x) ix1 = r_view.x;
1250 if (iy1 < r_view.y) iy1 = r_view.y;
1251 if (ix2 > r_view.x + r_view.width) ix2 = r_view.x + r_view.width;
1252 if (iy2 > r_view.y + r_view.height) iy2 = r_view.y + r_view.height;
1254 // if it is inside out, it's not visible
1255 if (ix2 <= ix1 || iy2 <= iy1)
1258 // the light area is visible, set up the scissor rectangle
1259 GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1260 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1261 //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1262 r_refdef.stats.lights_scissored++;
1266 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1268 float *vertex3f = rsurface_vertex3f + 3 * firstvertex;
1269 float *normal3f = rsurface_normal3f + 3 * firstvertex;
1270 float *color4f = rsurface_array_color4f + 4 * firstvertex;
1271 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1272 if (r_textureunits.integer >= 3)
1274 if (VectorLength2(diffusecolor) > 0)
1276 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1278 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1279 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1280 if ((dot = DotProduct(n, v)) < 0)
1282 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1283 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1286 VectorCopy(ambientcolor, color4f);
1287 if (r_refdef.fogenabled)
1289 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1290 VectorScale(color4f, f, color4f);
1297 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1299 VectorCopy(ambientcolor, color4f);
1300 if (r_refdef.fogenabled)
1303 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1304 f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1305 VectorScale(color4f, f, color4f);
1311 else if (r_textureunits.integer >= 2)
1313 if (VectorLength2(diffusecolor) > 0)
1315 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1317 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1318 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1320 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1321 if ((dot = DotProduct(n, v)) < 0)
1323 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1324 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1325 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1326 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1330 color4f[0] = ambientcolor[0] * distintensity;
1331 color4f[1] = ambientcolor[1] * distintensity;
1332 color4f[2] = ambientcolor[2] * distintensity;
1334 if (r_refdef.fogenabled)
1336 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1337 VectorScale(color4f, f, color4f);
1341 VectorClear(color4f);
1347 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1349 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1350 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1352 color4f[0] = ambientcolor[0] * distintensity;
1353 color4f[1] = ambientcolor[1] * distintensity;
1354 color4f[2] = ambientcolor[2] * distintensity;
1355 if (r_refdef.fogenabled)
1357 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1358 VectorScale(color4f, f, color4f);
1362 VectorClear(color4f);
1369 if (VectorLength2(diffusecolor) > 0)
1371 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1373 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1374 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1376 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1377 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1378 if ((dot = DotProduct(n, v)) < 0)
1380 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1381 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1382 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1383 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1387 color4f[0] = ambientcolor[0] * distintensity;
1388 color4f[1] = ambientcolor[1] * distintensity;
1389 color4f[2] = ambientcolor[2] * distintensity;
1391 if (r_refdef.fogenabled)
1393 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1394 VectorScale(color4f, f, color4f);
1398 VectorClear(color4f);
1404 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1406 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1407 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1409 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1410 color4f[0] = ambientcolor[0] * distintensity;
1411 color4f[1] = ambientcolor[1] * distintensity;
1412 color4f[2] = ambientcolor[2] * distintensity;
1413 if (r_refdef.fogenabled)
1415 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1416 VectorScale(color4f, f, color4f);
1420 VectorClear(color4f);
1427 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1429 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1432 float *out3f = rsurface_array_texcoord3f + 3 * firstvertex;
1433 const float *vertex3f = rsurface_vertex3f + 3 * firstvertex;
1434 const float *svector3f = rsurface_svector3f + 3 * firstvertex;
1435 const float *tvector3f = rsurface_tvector3f + 3 * firstvertex;
1436 const float *normal3f = rsurface_normal3f + 3 * firstvertex;
1438 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1440 VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1441 // the cubemap normalizes this for us
1442 out3f[0] = DotProduct(svector3f, lightdir);
1443 out3f[1] = DotProduct(tvector3f, lightdir);
1444 out3f[2] = DotProduct(normal3f, lightdir);
1448 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1451 float *out3f = rsurface_array_texcoord3f + 3 * firstvertex;
1452 const float *vertex3f = rsurface_vertex3f + 3 * firstvertex;
1453 const float *svector3f = rsurface_svector3f + 3 * firstvertex;
1454 const float *tvector3f = rsurface_tvector3f + 3 * firstvertex;
1455 const float *normal3f = rsurface_normal3f + 3 * firstvertex;
1456 float lightdir[3], eyedir[3], halfdir[3];
1457 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1459 VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1460 VectorNormalize(lightdir);
1461 VectorSubtract(rsurface_modelorg, vertex3f, eyedir);
1462 VectorNormalize(eyedir);
1463 VectorAdd(lightdir, eyedir, halfdir);
1464 // the cubemap normalizes this for us
1465 out3f[0] = DotProduct(svector3f, halfdir);
1466 out3f[1] = DotProduct(tvector3f, halfdir);
1467 out3f[2] = DotProduct(normal3f, halfdir);
1471 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)
1473 // used to display how many times a surface is lit for level design purposes
1474 GL_Color(0.1 * r_view.colorscale, 0.025 * r_view.colorscale, 0, 1);
1475 R_Mesh_ColorPointer(NULL, 0, 0);
1476 R_Mesh_ResetTextureState();
1477 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1480 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)
1482 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1483 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale);
1484 R_Mesh_TexCoordPointer(0, 2, rsurface_model->surfmesh.data_texcoordtexture2f, rsurface_model->surfmesh.vbo, rsurface_model->surfmesh.vbooffset_texcoordtexture2f);
1485 R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f, rsurface_svector3f_bufferobject, rsurface_svector3f_bufferoffset);
1486 R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f, rsurface_tvector3f_bufferobject, rsurface_tvector3f_bufferoffset);
1487 R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f, rsurface_normal3f_bufferobject, rsurface_normal3f_bufferoffset);
1488 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1490 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1492 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1493 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1495 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1499 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)
1501 // shared final code for all the dot3 layers
1503 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1504 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1506 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1507 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1511 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)
1514 // colorscale accounts for how much we multiply the brightness
1517 // mult is how many times the final pass of the lighting will be
1518 // performed to get more brightness than otherwise possible.
1520 // Limit mult to 64 for sanity sake.
1522 if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1524 // 3 3D combine path (Geforce3, Radeon 8500)
1525 memset(&m, 0, sizeof(m));
1526 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1527 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1528 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1529 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1530 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1531 m.tex[1] = R_GetTexture(basetexture);
1532 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1533 m.pointer_texcoord_bufferobject[1] = rsurface_model->surfmesh.vbo;
1534 m.pointer_texcoord_bufferoffset[1] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1535 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1536 m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1537 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1538 m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject;
1539 m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset;
1540 m.texmatrix[2] = r_shadow_entitytolight;
1541 GL_BlendFunc(GL_ONE, GL_ONE);
1543 else if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1545 // 2 3D combine path (Geforce3, original Radeon)
1546 memset(&m, 0, sizeof(m));
1547 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1548 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1549 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1550 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1551 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1552 m.tex[1] = R_GetTexture(basetexture);
1553 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1554 m.pointer_texcoord_bufferobject[1] = rsurface_model->surfmesh.vbo;
1555 m.pointer_texcoord_bufferoffset[1] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1556 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1557 GL_BlendFunc(GL_ONE, GL_ONE);
1559 else if (r_textureunits.integer >= 4 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1561 // 4 2D combine path (Geforce3, Radeon 8500)
1562 memset(&m, 0, sizeof(m));
1563 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1564 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1565 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1566 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1567 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1568 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1569 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1570 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1571 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1572 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1573 m.tex[2] = R_GetTexture(basetexture);
1574 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1575 m.pointer_texcoord_bufferobject[2] = rsurface_model->surfmesh.vbo;
1576 m.pointer_texcoord_bufferoffset[2] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1577 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1578 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1580 m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1581 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1582 m.pointer_texcoord_bufferobject[3] = rsurface_vertex3f_bufferobject;
1583 m.pointer_texcoord_bufferoffset[3] = rsurface_vertex3f_bufferoffset;
1584 m.texmatrix[3] = r_shadow_entitytolight;
1586 GL_BlendFunc(GL_ONE, GL_ONE);
1588 else if (r_textureunits.integer >= 3 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1590 // 3 2D combine path (Geforce3, original Radeon)
1591 memset(&m, 0, sizeof(m));
1592 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1593 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1594 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1595 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1596 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1597 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1598 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1599 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1600 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1601 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1602 m.tex[2] = R_GetTexture(basetexture);
1603 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1604 m.pointer_texcoord_bufferobject[2] = rsurface_model->surfmesh.vbo;
1605 m.pointer_texcoord_bufferoffset[2] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1606 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1607 GL_BlendFunc(GL_ONE, GL_ONE);
1611 // 2/2/2 2D combine path (any dot3 card)
1612 memset(&m, 0, sizeof(m));
1613 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1614 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1615 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1616 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1617 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1618 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1619 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1620 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1621 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1622 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1623 R_Mesh_TextureState(&m);
1624 GL_ColorMask(0,0,0,1);
1625 GL_BlendFunc(GL_ONE, GL_ZERO);
1626 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1629 memset(&m, 0, sizeof(m));
1630 m.tex[0] = R_GetTexture(basetexture);
1631 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1632 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1633 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1634 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1635 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1637 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1638 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1639 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1640 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1641 m.texmatrix[1] = r_shadow_entitytolight;
1643 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1645 // this final code is shared
1646 R_Mesh_TextureState(&m);
1647 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1650 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)
1653 // colorscale accounts for how much we multiply the brightness
1656 // mult is how many times the final pass of the lighting will be
1657 // performed to get more brightness than otherwise possible.
1659 // Limit mult to 64 for sanity sake.
1661 // generate normalization cubemap texcoords
1662 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1663 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1665 // 3/2 3D combine path (Geforce3, Radeon 8500)
1666 memset(&m, 0, sizeof(m));
1667 m.tex[0] = R_GetTexture(normalmaptexture);
1668 m.texcombinergb[0] = GL_REPLACE;
1669 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1670 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1671 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1672 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1673 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1674 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1675 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1676 m.pointer_texcoord_bufferobject[1] = 0;
1677 m.pointer_texcoord_bufferoffset[1] = 0;
1678 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1679 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1680 m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject;
1681 m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset;
1682 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1683 R_Mesh_TextureState(&m);
1684 GL_ColorMask(0,0,0,1);
1685 GL_BlendFunc(GL_ONE, GL_ZERO);
1686 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1689 memset(&m, 0, sizeof(m));
1690 m.tex[0] = R_GetTexture(basetexture);
1691 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1692 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1693 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1694 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1695 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1697 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1698 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1699 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1700 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1701 m.texmatrix[1] = r_shadow_entitytolight;
1703 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1705 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1707 // 1/2/2 3D combine path (original Radeon)
1708 memset(&m, 0, sizeof(m));
1709 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1710 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1711 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1712 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1713 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1714 R_Mesh_TextureState(&m);
1715 GL_ColorMask(0,0,0,1);
1716 GL_BlendFunc(GL_ONE, GL_ZERO);
1717 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1720 memset(&m, 0, sizeof(m));
1721 m.tex[0] = R_GetTexture(normalmaptexture);
1722 m.texcombinergb[0] = GL_REPLACE;
1723 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1724 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1725 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1726 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1727 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1728 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1729 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1730 m.pointer_texcoord_bufferobject[1] = 0;
1731 m.pointer_texcoord_bufferoffset[1] = 0;
1732 R_Mesh_TextureState(&m);
1733 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1734 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1737 memset(&m, 0, sizeof(m));
1738 m.tex[0] = R_GetTexture(basetexture);
1739 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1740 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1741 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1742 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1743 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1745 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1746 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1747 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1748 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1749 m.texmatrix[1] = r_shadow_entitytolight;
1751 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1753 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1755 // 2/2 3D combine path (original Radeon)
1756 memset(&m, 0, sizeof(m));
1757 m.tex[0] = R_GetTexture(normalmaptexture);
1758 m.texcombinergb[0] = GL_REPLACE;
1759 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1760 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1761 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1762 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1763 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1764 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1765 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1766 m.pointer_texcoord_bufferobject[1] = 0;
1767 m.pointer_texcoord_bufferoffset[1] = 0;
1768 R_Mesh_TextureState(&m);
1769 GL_ColorMask(0,0,0,1);
1770 GL_BlendFunc(GL_ONE, GL_ZERO);
1771 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1774 memset(&m, 0, sizeof(m));
1775 m.tex[0] = R_GetTexture(basetexture);
1776 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1777 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1778 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1779 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1780 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1781 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1782 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1783 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1784 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1785 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1787 else if (r_textureunits.integer >= 4)
1789 // 4/2 2D combine path (Geforce3, Radeon 8500)
1790 memset(&m, 0, sizeof(m));
1791 m.tex[0] = R_GetTexture(normalmaptexture);
1792 m.texcombinergb[0] = GL_REPLACE;
1793 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1794 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1795 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1796 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1797 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1798 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1799 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1800 m.pointer_texcoord_bufferobject[1] = 0;
1801 m.pointer_texcoord_bufferoffset[1] = 0;
1802 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1803 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1804 m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject;
1805 m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset;
1806 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1807 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1808 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1809 m.pointer_texcoord_bufferobject[3] = rsurface_vertex3f_bufferobject;
1810 m.pointer_texcoord_bufferoffset[3] = rsurface_vertex3f_bufferoffset;
1811 m.texmatrix[3] = r_shadow_entitytoattenuationz;
1812 R_Mesh_TextureState(&m);
1813 GL_ColorMask(0,0,0,1);
1814 GL_BlendFunc(GL_ONE, GL_ZERO);
1815 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1818 memset(&m, 0, sizeof(m));
1819 m.tex[0] = R_GetTexture(basetexture);
1820 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1821 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1822 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1823 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1824 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1826 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1827 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1828 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1829 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1830 m.texmatrix[1] = r_shadow_entitytolight;
1832 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1836 // 2/2/2 2D combine path (any dot3 card)
1837 memset(&m, 0, sizeof(m));
1838 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1839 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1840 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1841 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1842 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1843 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1844 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1845 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1846 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1847 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1848 R_Mesh_TextureState(&m);
1849 GL_ColorMask(0,0,0,1);
1850 GL_BlendFunc(GL_ONE, GL_ZERO);
1851 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1854 memset(&m, 0, sizeof(m));
1855 m.tex[0] = R_GetTexture(normalmaptexture);
1856 m.texcombinergb[0] = GL_REPLACE;
1857 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1858 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1859 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1860 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1861 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1862 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1863 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1864 m.pointer_texcoord_bufferobject[1] = 0;
1865 m.pointer_texcoord_bufferoffset[1] = 0;
1866 R_Mesh_TextureState(&m);
1867 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1868 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1871 memset(&m, 0, sizeof(m));
1872 m.tex[0] = R_GetTexture(basetexture);
1873 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1874 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1875 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1876 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1877 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1879 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1880 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1881 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1882 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1883 m.texmatrix[1] = r_shadow_entitytolight;
1885 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1887 // this final code is shared
1888 R_Mesh_TextureState(&m);
1889 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1892 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)
1894 float glossexponent;
1896 // FIXME: detect blendsquare!
1897 //if (!gl_support_blendsquare)
1900 // generate normalization cubemap texcoords
1901 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1902 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1904 // 2/0/0/1/2 3D combine blendsquare path
1905 memset(&m, 0, sizeof(m));
1906 m.tex[0] = R_GetTexture(normalmaptexture);
1907 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1908 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1909 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1910 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1911 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1912 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1913 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1914 m.pointer_texcoord_bufferobject[1] = 0;
1915 m.pointer_texcoord_bufferoffset[1] = 0;
1916 R_Mesh_TextureState(&m);
1917 GL_ColorMask(0,0,0,1);
1918 // this squares the result
1919 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1920 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1922 // second and third pass
1923 R_Mesh_ResetTextureState();
1924 // square alpha in framebuffer a few times to make it shiny
1925 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1926 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1927 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1930 memset(&m, 0, sizeof(m));
1931 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1932 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1933 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1934 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1935 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1936 R_Mesh_TextureState(&m);
1937 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1938 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1941 memset(&m, 0, sizeof(m));
1942 m.tex[0] = R_GetTexture(glosstexture);
1943 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1944 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1945 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1946 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1947 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1949 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1950 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1951 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1952 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1953 m.texmatrix[1] = r_shadow_entitytolight;
1955 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1957 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1959 // 2/0/0/2 3D combine blendsquare path
1960 memset(&m, 0, sizeof(m));
1961 m.tex[0] = R_GetTexture(normalmaptexture);
1962 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1963 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1964 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1965 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1966 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1967 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1968 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1969 m.pointer_texcoord_bufferobject[1] = 0;
1970 m.pointer_texcoord_bufferoffset[1] = 0;
1971 R_Mesh_TextureState(&m);
1972 GL_ColorMask(0,0,0,1);
1973 // this squares the result
1974 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1975 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1977 // second and third pass
1978 R_Mesh_ResetTextureState();
1979 // square alpha in framebuffer a few times to make it shiny
1980 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1981 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1982 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1985 memset(&m, 0, sizeof(m));
1986 m.tex[0] = R_GetTexture(glosstexture);
1987 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1988 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1989 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1990 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1991 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1992 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1993 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1994 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1995 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1996 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2000 // 2/0/0/2/2 2D combine blendsquare path
2001 memset(&m, 0, sizeof(m));
2002 m.tex[0] = R_GetTexture(normalmaptexture);
2003 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
2004 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
2005 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
2006 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
2007 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2008 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2009 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
2010 m.pointer_texcoord_bufferobject[1] = 0;
2011 m.pointer_texcoord_bufferoffset[1] = 0;
2012 R_Mesh_TextureState(&m);
2013 GL_ColorMask(0,0,0,1);
2014 // this squares the result
2015 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2016 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2018 // second and third pass
2019 R_Mesh_ResetTextureState();
2020 // square alpha in framebuffer a few times to make it shiny
2021 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2022 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2023 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2026 memset(&m, 0, sizeof(m));
2027 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2028 m.pointer_texcoord3f[0] = rsurface_vertex3f;
2029 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
2030 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
2031 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2032 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2033 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2034 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
2035 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
2036 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2037 R_Mesh_TextureState(&m);
2038 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2039 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2042 memset(&m, 0, sizeof(m));
2043 m.tex[0] = R_GetTexture(glosstexture);
2044 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
2045 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
2046 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
2047 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
2048 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
2050 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
2051 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2052 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
2053 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
2054 m.texmatrix[1] = r_shadow_entitytolight;
2056 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2058 // this final code is shared
2059 R_Mesh_TextureState(&m);
2060 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
2063 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)
2065 // ARB path (any Geforce, any Radeon)
2066 qboolean doambient = ambientscale > 0;
2067 qboolean dodiffuse = diffusescale > 0;
2068 qboolean dospecular = specularscale > 0;
2069 if (!doambient && !dodiffuse && !dospecular)
2071 R_Mesh_ColorPointer(NULL, 0, 0);
2073 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, ambientscale * r_view.colorscale);
2075 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_view.colorscale);
2079 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, ambientscale * r_view.colorscale);
2081 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_view.colorscale);
2086 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, ambientscale * r_view.colorscale);
2088 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_view.colorscale);
2091 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale);
2094 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)
2101 int newnumtriangles;
2105 int newelements[4096*3];
2106 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2107 for (renders = 0;renders < 64;renders++)
2112 newnumtriangles = 0;
2114 // due to low fillrate on the cards this vertex lighting path is
2115 // designed for, we manually cull all triangles that do not
2116 // contain a lit vertex
2117 // this builds batches of triangles from multiple surfaces and
2118 // renders them at once
2119 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2121 if (VectorLength2(rsurface_array_color4f + e[0] * 4) + VectorLength2(rsurface_array_color4f + e[1] * 4) + VectorLength2(rsurface_array_color4f + e[2] * 4) >= 0.01)
2123 if (newnumtriangles)
2125 newfirstvertex = min(newfirstvertex, e[0]);
2126 newlastvertex = max(newlastvertex, e[0]);
2130 newfirstvertex = e[0];
2131 newlastvertex = e[0];
2133 newfirstvertex = min(newfirstvertex, e[1]);
2134 newlastvertex = max(newlastvertex, e[1]);
2135 newfirstvertex = min(newfirstvertex, e[2]);
2136 newlastvertex = max(newlastvertex, e[2]);
2142 if (newnumtriangles >= (int)(sizeof(newelements)/sizeof(float[3])))
2144 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2145 newnumtriangles = 0;
2151 if (newnumtriangles >= 1)
2153 // if all triangles are included, use the original array to take advantage of the bufferobject if possible
2154 if (newnumtriangles == numtriangles)
2155 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2157 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2160 // if we couldn't find any lit triangles, exit early
2163 // now reduce the intensity for the next overbright pass
2164 // we have to clamp to 0 here incase the drivers have improper
2165 // handling of negative colors
2166 // (some old drivers even have improper handling of >1 color)
2168 for (i = 0, c = rsurface_array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2170 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2172 c[0] = max(0, c[0] - 1);
2173 c[1] = max(0, c[1] - 1);
2174 c[2] = max(0, c[2] - 1);
2186 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)
2188 // OpenGL 1.1 path (anything)
2189 model_t *model = rsurface_entity->model;
2190 float ambientcolorbase[3], diffusecolorbase[3];
2191 float ambientcolorpants[3], diffusecolorpants[3];
2192 float ambientcolorshirt[3], diffusecolorshirt[3];
2194 VectorScale(lightcolorbase, ambientscale * 2 * r_view.colorscale, ambientcolorbase);
2195 VectorScale(lightcolorbase, diffusescale * 2 * r_view.colorscale, diffusecolorbase);
2196 VectorScale(lightcolorpants, ambientscale * 2 * r_view.colorscale, ambientcolorpants);
2197 VectorScale(lightcolorpants, diffusescale * 2 * r_view.colorscale, diffusecolorpants);
2198 VectorScale(lightcolorshirt, ambientscale * 2 * r_view.colorscale, ambientcolorshirt);
2199 VectorScale(lightcolorshirt, diffusescale * 2 * r_view.colorscale, diffusecolorshirt);
2200 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2201 R_Mesh_ColorPointer(rsurface_array_color4f, 0, 0);
2202 memset(&m, 0, sizeof(m));
2203 m.tex[0] = R_GetTexture(basetexture);
2204 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
2205 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
2206 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
2207 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
2208 if (r_textureunits.integer >= 2)
2211 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2212 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2213 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2214 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
2215 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
2216 if (r_textureunits.integer >= 3)
2218 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2219 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2220 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2221 m.pointer_texcoord3f[2] = rsurface_vertex3f;
2222 m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject;
2223 m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset;
2226 R_Mesh_TextureState(&m);
2227 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2228 R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorbase, ambientcolorbase);
2231 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2232 R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorpants, ambientcolorpants);
2236 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2237 R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorshirt, ambientcolorshirt);
2241 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset)
2243 float ambientscale, diffusescale, specularscale;
2244 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2245 // calculate colors to render this texture with
2246 lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * rsurface_entity->colormod[0] * rsurface_texture->currentalpha;
2247 lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * rsurface_entity->colormod[1] * rsurface_texture->currentalpha;
2248 lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * rsurface_entity->colormod[2] * rsurface_texture->currentalpha;
2249 ambientscale = r_shadow_rtlight->ambientscale;
2250 diffusescale = r_shadow_rtlight->diffusescale;
2251 specularscale = r_shadow_rtlight->specularscale * rsurface_texture->specularscale;
2252 if (!r_shadow_usenormalmap.integer)
2254 ambientscale += 1.0f * diffusescale;
2258 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2260 GL_DepthRange(0, (rsurface_texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
2261 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
2262 GL_CullFace((rsurface_texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
2263 if (rsurface_texture->colormapping)
2265 qboolean dopants = rsurface_texture->currentskinframe->pants != NULL && VectorLength2(rsurface_entity->colormap_pantscolor) >= (1.0f / 1048576.0f);
2266 qboolean doshirt = rsurface_texture->currentskinframe->shirt != NULL && VectorLength2(rsurface_entity->colormap_shirtcolor) >= (1.0f / 1048576.0f);
2269 lightcolorpants[0] = lightcolorbase[0] * rsurface_entity->colormap_pantscolor[0];
2270 lightcolorpants[1] = lightcolorbase[1] * rsurface_entity->colormap_pantscolor[1];
2271 lightcolorpants[2] = lightcolorbase[2] * rsurface_entity->colormap_pantscolor[2];
2274 VectorClear(lightcolorpants);
2277 lightcolorshirt[0] = lightcolorbase[0] * rsurface_entity->colormap_shirtcolor[0];
2278 lightcolorshirt[1] = lightcolorbase[1] * rsurface_entity->colormap_shirtcolor[1];
2279 lightcolorshirt[2] = lightcolorbase[2] * rsurface_entity->colormap_shirtcolor[2];
2282 VectorClear(lightcolorshirt);
2283 switch (r_shadow_rendermode)
2285 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2286 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2287 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);
2289 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2290 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);
2292 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2293 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);
2295 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2296 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);
2299 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2305 switch (r_shadow_rendermode)
2307 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2308 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2309 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);
2311 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2312 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);
2314 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2315 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);
2317 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2318 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);
2321 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2327 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)
2329 matrix4x4_t tempmatrix = *matrix;
2330 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2332 // if this light has been compiled before, free the associated data
2333 R_RTLight_Uncompile(rtlight);
2335 // clear it completely to avoid any lingering data
2336 memset(rtlight, 0, sizeof(*rtlight));
2338 // copy the properties
2339 rtlight->matrix_lighttoworld = tempmatrix;
2340 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2341 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2342 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2343 VectorCopy(color, rtlight->color);
2344 rtlight->cubemapname[0] = 0;
2345 if (cubemapname && cubemapname[0])
2346 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2347 rtlight->shadow = shadow;
2348 rtlight->corona = corona;
2349 rtlight->style = style;
2350 rtlight->isstatic = isstatic;
2351 rtlight->coronasizescale = coronasizescale;
2352 rtlight->ambientscale = ambientscale;
2353 rtlight->diffusescale = diffusescale;
2354 rtlight->specularscale = specularscale;
2355 rtlight->flags = flags;
2357 // compute derived data
2358 //rtlight->cullradius = rtlight->radius;
2359 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2360 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2361 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2362 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2363 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2364 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2365 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2368 // compiles rtlight geometry
2369 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2370 void R_RTLight_Compile(rtlight_t *rtlight)
2373 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2374 int lighttris, shadowtris, shadowmeshes, shadowmeshtris;
2375 entity_render_t *ent = r_refdef.worldentity;
2376 model_t *model = r_refdef.worldmodel;
2377 unsigned char *data;
2379 // compile the light
2380 rtlight->compiled = true;
2381 rtlight->static_numleafs = 0;
2382 rtlight->static_numleafpvsbytes = 0;
2383 rtlight->static_leaflist = NULL;
2384 rtlight->static_leafpvs = NULL;
2385 rtlight->static_numsurfaces = 0;
2386 rtlight->static_surfacelist = NULL;
2387 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2388 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2389 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2390 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2391 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2392 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2394 if (model && model->GetLightInfo)
2396 // this variable must be set for the CompileShadowVolume code
2397 r_shadow_compilingrtlight = rtlight;
2398 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);
2399 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);
2400 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2401 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2402 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2403 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2404 rtlight->static_numsurfaces = numsurfaces;
2405 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2406 rtlight->static_numleafs = numleafs;
2407 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2408 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2409 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2410 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2411 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2412 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2413 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2414 if (rtlight->static_numsurfaces)
2415 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2416 if (rtlight->static_numleafs)
2417 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2418 if (rtlight->static_numleafpvsbytes)
2419 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2420 if (rtlight->static_numshadowtrispvsbytes)
2421 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2422 if (rtlight->static_numlighttrispvsbytes)
2423 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2424 if (model->CompileShadowVolume && rtlight->shadow)
2425 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2426 // now we're done compiling the rtlight
2427 r_shadow_compilingrtlight = NULL;
2431 // use smallest available cullradius - box radius or light radius
2432 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2433 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2437 if (rtlight->static_meshchain_shadow)
2440 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2443 shadowmeshtris += mesh->numtriangles;
2448 if (rtlight->static_numlighttrispvsbytes)
2449 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2450 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2454 if (rtlight->static_numlighttrispvsbytes)
2455 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2456 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2459 if (developer.integer >= 10)
2460 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);
2463 void R_RTLight_Uncompile(rtlight_t *rtlight)
2465 if (rtlight->compiled)
2467 if (rtlight->static_meshchain_shadow)
2468 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2469 rtlight->static_meshchain_shadow = NULL;
2470 // these allocations are grouped
2471 if (rtlight->static_surfacelist)
2472 Mem_Free(rtlight->static_surfacelist);
2473 rtlight->static_numleafs = 0;
2474 rtlight->static_numleafpvsbytes = 0;
2475 rtlight->static_leaflist = NULL;
2476 rtlight->static_leafpvs = NULL;
2477 rtlight->static_numsurfaces = 0;
2478 rtlight->static_surfacelist = NULL;
2479 rtlight->static_numshadowtrispvsbytes = 0;
2480 rtlight->static_shadowtrispvs = NULL;
2481 rtlight->static_numlighttrispvsbytes = 0;
2482 rtlight->static_lighttrispvs = NULL;
2483 rtlight->compiled = false;
2487 void R_Shadow_UncompileWorldLights(void)
2490 for (light = r_shadow_worldlightchain;light;light = light->next)
2491 R_RTLight_Uncompile(&light->rtlight);
2494 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2498 // reset the count of frustum planes
2499 // see r_shadow_rtlight_frustumplanes definition for how much this array
2501 r_shadow_rtlight_numfrustumplanes = 0;
2504 // generate a deformed frustum that includes the light origin, this is
2505 // used to cull shadow casting surfaces that can not possibly cast a
2506 // shadow onto the visible light-receiving surfaces, which can be a
2509 // if the light origin is onscreen the result will be 4 planes exactly
2510 // if the light origin is offscreen on only one axis the result will
2511 // be exactly 5 planes (split-side case)
2512 // if the light origin is offscreen on two axes the result will be
2513 // exactly 4 planes (stretched corner case)
2514 for (i = 0;i < 4;i++)
2516 // quickly reject standard frustum planes that put the light
2517 // origin outside the frustum
2518 if (PlaneDiff(rtlight->shadoworigin, &r_view.frustum[i]) < -0.03125)
2521 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = r_view.frustum[i];
2523 // if all the standard frustum planes were accepted, the light is onscreen
2524 // otherwise we need to generate some more planes below...
2525 if (r_shadow_rtlight_numfrustumplanes < 4)
2527 // at least one of the stock frustum planes failed, so we need to
2528 // create one or two custom planes to enclose the light origin
2529 for (i = 0;i < 4;i++)
2531 // create a plane using the view origin and light origin, and a
2532 // single point from the frustum corner set
2533 TriangleNormal(r_view.origin, r_view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2534 VectorNormalize(plane.normal);
2535 plane.dist = DotProduct(r_view.origin, plane.normal);
2536 // see if this plane is backwards and flip it if so
2537 for (j = 0;j < 4;j++)
2538 if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2542 VectorNegate(plane.normal, plane.normal);
2544 // flipped plane, test again to see if it is now valid
2545 for (j = 0;j < 4;j++)
2546 if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2548 // if the plane is still not valid, then it is dividing the
2549 // frustum and has to be rejected
2553 // we have created a valid plane, compute extra info
2554 PlaneClassify(&plane);
2556 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = plane;
2558 // if we've found 5 frustum planes then we have constructed a
2559 // proper split-side case and do not need to keep searching for
2560 // planes to enclose the light origin
2561 if (r_shadow_rtlight_numfrustumplanes == 5)
2569 for (i = 0;i < r_shadow_rtlight_numfrustumplanes;i++)
2571 plane = r_shadow_rtlight_frustumplanes[i];
2572 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));
2577 // now add the light-space box planes if the light box is rotated, as any
2578 // caster outside the oriented light box is irrelevant (even if it passed
2579 // the worldspace light box, which is axial)
2580 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
2582 for (i = 0;i < 6;i++)
2586 v[i >> 1] = (i & 1) ? -1 : 1;
2587 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
2588 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
2589 plane.dist = VectorNormalizeLength(plane.normal);
2590 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
2591 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = plane;
2597 // add the world-space reduced box planes
2598 for (i = 0;i < 6;i++)
2600 VectorClear(plane.normal);
2601 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
2602 plane.dist = (i & 1) ? -r_shadow_rtlight_cullmaxs[i >> 1] : r_shadow_rtlight_cullmins[i >> 1];
2603 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = plane;
2612 // reduce all plane distances to tightly fit the rtlight cull box, which
2614 VectorSet(points[0], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmins[2]);
2615 VectorSet(points[1], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmins[2]);
2616 VectorSet(points[2], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmins[2]);
2617 VectorSet(points[3], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmins[2]);
2618 VectorSet(points[4], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmaxs[2]);
2619 VectorSet(points[5], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmaxs[2]);
2620 VectorSet(points[6], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmaxs[2]);
2621 VectorSet(points[7], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmaxs[2]);
2622 oldnum = r_shadow_rtlight_numfrustumplanes;
2623 r_shadow_rtlight_numfrustumplanes = 0;
2624 for (j = 0;j < oldnum;j++)
2626 // find the nearest point on the box to this plane
2627 bestdist = DotProduct(r_shadow_rtlight_frustumplanes[j].normal, points[0]);
2628 for (i = 1;i < 8;i++)
2630 dist = DotProduct(r_shadow_rtlight_frustumplanes[j].normal, points[i]);
2631 if (bestdist > dist)
2634 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);
2635 // if the nearest point is near or behind the plane, we want this
2636 // plane, otherwise the plane is useless as it won't cull anything
2637 if (r_shadow_rtlight_frustumplanes[j].dist < bestdist + 0.03125)
2639 PlaneClassify(&r_shadow_rtlight_frustumplanes[j]);
2640 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = r_shadow_rtlight_frustumplanes[j];
2647 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2649 RSurf_ActiveWorldEntity();
2650 if (r_shadow_rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2654 for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2656 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2657 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
2658 GL_LockArrays(0, mesh->numverts);
2659 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2661 // decrement stencil if backface is behind depthbuffer
2662 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
2663 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2664 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2665 // increment stencil if frontface is behind depthbuffer
2666 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2667 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2669 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2670 GL_LockArrays(0, 0);
2674 else if (numsurfaces && r_refdef.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
2677 int surfacelistindex;
2678 msurface_t *surface;
2679 R_Shadow_PrepareShadowMark(r_refdef.worldmodel->brush.shadowmesh->numtriangles);
2680 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2682 surface = r_refdef.worldmodel->data_surfaces + surfacelist[surfacelistindex];
2683 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
2684 if (CHECKPVSBIT(trispvs, t))
2685 shadowmarklist[numshadowmark++] = t;
2687 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);
2689 else if (numsurfaces)
2690 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);
2693 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
2695 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2696 vec_t relativeshadowradius;
2697 RSurf_ActiveModelEntity(ent, false, false);
2698 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, relativeshadoworigin);
2699 relativeshadowradius = r_shadow_rtlight->radius / ent->scale;
2700 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2701 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2702 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2703 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2704 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2705 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2706 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2709 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2711 // set up properties for rendering light onto this entity
2712 RSurf_ActiveModelEntity(ent, true, true);
2713 Matrix4x4_Concat(&r_shadow_entitytolight, &r_shadow_rtlight->matrix_worldtolight, &ent->matrix);
2714 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2715 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2716 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2717 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2718 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2721 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2723 if (!r_refdef.worldmodel->DrawLight)
2726 // set up properties for rendering light onto this entity
2727 RSurf_ActiveWorldEntity();
2728 r_shadow_entitytolight = r_shadow_rtlight->matrix_worldtolight;
2729 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2730 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2731 VectorCopy(r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2732 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2733 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2735 r_refdef.worldmodel->DrawLight(r_refdef.worldentity, numsurfaces, surfacelist, trispvs);
2738 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2740 model_t *model = ent->model;
2741 if (!model->DrawLight)
2744 R_Shadow_SetupEntityLight(ent);
2746 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist, NULL);
2749 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2753 int numleafs, numsurfaces;
2754 int *leaflist, *surfacelist;
2755 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
2756 int numlightentities;
2757 int numshadowentities;
2758 entity_render_t *lightentities[MAX_EDICTS];
2759 entity_render_t *shadowentities[MAX_EDICTS];
2761 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2762 // skip lights that are basically invisible (color 0 0 0)
2763 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2766 // loading is done before visibility checks because loading should happen
2767 // all at once at the start of a level, not when it stalls gameplay.
2768 // (especially important to benchmarks)
2770 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2771 R_RTLight_Compile(rtlight);
2773 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2775 // look up the light style value at this time
2776 f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2777 VectorScale(rtlight->color, f, rtlight->currentcolor);
2779 if (rtlight->selected)
2781 f = 2 + sin(realtime * M_PI * 4.0);
2782 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2786 // if lightstyle is currently off, don't draw the light
2787 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2790 // if the light box is offscreen, skip it
2791 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2794 VectorCopy(rtlight->cullmins, r_shadow_rtlight_cullmins);
2795 VectorCopy(rtlight->cullmaxs, r_shadow_rtlight_cullmaxs);
2797 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2799 // compiled light, world available and can receive realtime lighting
2800 // retrieve leaf information
2801 numleafs = rtlight->static_numleafs;
2802 leaflist = rtlight->static_leaflist;
2803 leafpvs = rtlight->static_leafpvs;
2804 numsurfaces = rtlight->static_numsurfaces;
2805 surfacelist = rtlight->static_surfacelist;
2806 shadowtrispvs = rtlight->static_shadowtrispvs;
2807 lighttrispvs = rtlight->static_lighttrispvs;
2809 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2811 // dynamic light, world available and can receive realtime lighting
2812 // calculate lit surfaces and leafs
2813 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);
2814 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);
2815 leaflist = r_shadow_buffer_leaflist;
2816 leafpvs = r_shadow_buffer_leafpvs;
2817 surfacelist = r_shadow_buffer_surfacelist;
2818 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
2819 lighttrispvs = r_shadow_buffer_lighttrispvs;
2820 // if the reduced leaf bounds are offscreen, skip it
2821 if (R_CullBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2832 shadowtrispvs = NULL;
2833 lighttrispvs = NULL;
2835 // check if light is illuminating any visible leafs
2838 for (i = 0;i < numleafs;i++)
2839 if (r_viewcache.world_leafvisible[leaflist[i]])
2844 // set up a scissor rectangle for this light
2845 if (R_Shadow_ScissorForBBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2848 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
2850 // make a list of lit entities and shadow casting entities
2851 numlightentities = 0;
2852 numshadowentities = 0;
2853 // add dynamic entities that are lit by the light
2854 if (r_drawentities.integer)
2856 for (i = 0;i < r_refdef.numentities;i++)
2859 entity_render_t *ent = r_refdef.entities[i];
2861 if (!BoxesOverlap(ent->mins, ent->maxs, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2863 // skip the object entirely if it is not within the valid
2864 // shadow-casting region (which includes the lit region)
2865 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, r_shadow_rtlight_numfrustumplanes, r_shadow_rtlight_frustumplanes))
2867 if (!(model = ent->model))
2869 if (r_viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
2871 // this entity wants to receive light, is visible, and is
2872 // inside the light box
2873 // TODO: check if the surfaces in the model can receive light
2874 // so now check if it's in a leaf seen by the light
2875 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2877 lightentities[numlightentities++] = ent;
2878 // since it is lit, it probably also casts a shadow...
2879 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2880 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2881 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2882 shadowentities[numshadowentities++] = ent;
2884 else if (ent->flags & RENDER_SHADOW)
2886 // this entity is not receiving light, but may still need to
2888 // TODO: check if the surfaces in the model can cast shadow
2889 // now check if it is in a leaf seen by the light
2890 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2892 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2893 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2894 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2895 shadowentities[numshadowentities++] = ent;
2900 // return if there's nothing at all to light
2901 if (!numlightentities && !numsurfaces)
2904 // don't let sound skip if going slow
2905 if (r_refdef.extraupdate)
2908 // make this the active rtlight for rendering purposes
2909 R_Shadow_RenderMode_ActiveLight(rtlight);
2910 // count this light in the r_speeds
2911 r_refdef.stats.lights++;
2914 if (numsurfaces + numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2916 // draw stencil shadow volumes to mask off pixels that are in shadow
2917 // so that they won't receive lighting
2921 R_Shadow_RenderMode_StencilShadowVolumes();
2923 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
2924 for (i = 0;i < numshadowentities;i++)
2925 R_Shadow_DrawEntityShadow(shadowentities[i]);
2928 // optionally draw visible shape of the shadow volumes
2929 // for performance analysis by level designers
2930 if (r_showshadowvolumes.integer)
2932 R_Shadow_RenderMode_VisibleShadowVolumes();
2934 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
2935 for (i = 0;i < numshadowentities;i++)
2936 R_Shadow_DrawEntityShadow(shadowentities[i]);
2940 if (numsurfaces + numlightentities)
2942 // draw lighting in the unmasked areas
2943 R_Shadow_RenderMode_Lighting(usestencil, false);
2945 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
2946 for (i = 0;i < numlightentities;i++)
2947 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2949 // optionally draw the illuminated areas
2950 // for performance analysis by level designers
2951 if (r_showlighting.integer)
2953 R_Shadow_RenderMode_VisibleLighting(usestencil && !r_showdisabledepthtest.integer, false);
2955 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
2956 for (i = 0;i < numlightentities;i++)
2957 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2962 void R_Shadow_DrawLightSprites(void);
2963 void R_ShadowVolumeLighting(qboolean visible)
2968 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2969 R_Shadow_EditLights_Reload_f();
2971 if (r_editlights.integer)
2972 R_Shadow_DrawLightSprites();
2974 R_Shadow_RenderMode_Begin();
2976 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2977 if (r_shadow_debuglight.integer >= 0)
2979 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2980 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2981 R_DrawRTLight(&light->rtlight, visible);
2984 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2985 if (light->flags & flag)
2986 R_DrawRTLight(&light->rtlight, visible);
2987 if (r_refdef.rtdlight)
2988 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
2989 R_DrawRTLight(&r_refdef.lights[lnum], visible);
2991 R_Shadow_RenderMode_End();
2994 extern void R_SetupView(const matrix4x4_t *matrix);
2995 extern cvar_t r_shadows_throwdistance;
2996 void R_DrawModelShadows(void)
2999 float relativethrowdistance;
3000 entity_render_t *ent;
3001 vec3_t relativelightorigin;
3002 vec3_t relativelightdirection;
3003 vec3_t relativeshadowmins, relativeshadowmaxs;
3006 if (!r_drawentities.integer || !gl_stencil)
3010 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
3012 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3014 if (gl_ext_separatestencil.integer)
3015 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
3016 else if (gl_ext_stenciltwoside.integer)
3017 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
3019 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
3021 R_Shadow_RenderMode_StencilShadowVolumes();
3023 for (i = 0;i < r_refdef.numentities;i++)
3025 ent = r_refdef.entities[i];
3026 // cast shadows from anything that is not a submodel of the map
3027 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
3029 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3030 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3031 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3032 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3033 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3034 RSurf_ActiveModelEntity(ent, false, false);
3035 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
3039 // not really the right mode, but this will disable any silly stencil features
3040 R_Shadow_RenderMode_VisibleLighting(true, true);
3042 // vertex coordinates for a quad that covers the screen exactly
3043 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
3044 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
3045 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
3046 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
3048 // set up ortho view for rendering this pass
3049 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
3050 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
3051 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
3052 GL_ScissorTest(true);
3053 R_Mesh_Matrix(&identitymatrix);
3054 R_Mesh_ResetTextureState();
3055 R_Mesh_VertexPointer(vertex3f, 0, 0);
3056 R_Mesh_ColorPointer(NULL, 0, 0);
3058 // set up a 50% darkening blend on shadowed areas
3059 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3060 GL_DepthRange(0, 1);
3061 GL_DepthTest(false);
3062 GL_DepthMask(false);
3063 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
3064 GL_Color(0, 0, 0, 0.5);
3065 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
3066 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
3067 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
3068 qglStencilMask(~0);CHECKGLERROR
3069 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3070 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
3072 // apply the blend to the shadowed areas
3073 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3075 // restoring the perspective view is done by R_RenderScene
3076 //R_SetupView(&r_view.matrix);
3078 // restore other state to normal
3079 R_Shadow_RenderMode_End();
3083 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3084 typedef struct suffixinfo_s
3087 qboolean flipx, flipy, flipdiagonal;
3090 static suffixinfo_t suffix[3][6] =
3093 {"px", false, false, false},
3094 {"nx", false, false, false},
3095 {"py", false, false, false},
3096 {"ny", false, false, false},
3097 {"pz", false, false, false},
3098 {"nz", false, false, false}
3101 {"posx", false, false, false},
3102 {"negx", false, false, false},
3103 {"posy", false, false, false},
3104 {"negy", false, false, false},
3105 {"posz", false, false, false},
3106 {"negz", false, false, false}
3109 {"rt", true, false, true},
3110 {"lf", false, true, true},
3111 {"ft", true, true, false},
3112 {"bk", false, false, false},
3113 {"up", true, false, true},
3114 {"dn", true, false, true}
3118 static int componentorder[4] = {0, 1, 2, 3};
3120 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3122 int i, j, cubemapsize;
3123 unsigned char *cubemappixels, *image_rgba;
3124 rtexture_t *cubemaptexture;
3126 // must start 0 so the first loadimagepixels has no requested width/height
3128 cubemappixels = NULL;
3129 cubemaptexture = NULL;
3130 // keep trying different suffix groups (posx, px, rt) until one loads
3131 for (j = 0;j < 3 && !cubemappixels;j++)
3133 // load the 6 images in the suffix group
3134 for (i = 0;i < 6;i++)
3136 // generate an image name based on the base and and suffix
3137 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3139 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
3141 // an image loaded, make sure width and height are equal
3142 if (image_width == image_height)
3144 // if this is the first image to load successfully, allocate the cubemap memory
3145 if (!cubemappixels && image_width >= 1)
3147 cubemapsize = image_width;
3148 // note this clears to black, so unavailable sides are black
3149 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3151 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3153 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);
3156 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3158 Mem_Free(image_rgba);
3162 // if a cubemap loaded, upload it
3165 if (!r_shadow_filters_texturepool)
3166 r_shadow_filters_texturepool = R_AllocTexturePool();
3167 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
3168 Mem_Free(cubemappixels);
3172 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3173 for (j = 0;j < 3;j++)
3174 for (i = 0;i < 6;i++)
3175 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3176 Con_Print(" and was unable to find any of them.\n");
3178 return cubemaptexture;
3181 rtexture_t *R_Shadow_Cubemap(const char *basename)
3184 for (i = 0;i < numcubemaps;i++)
3185 if (!strcasecmp(cubemaps[i].basename, basename))
3186 return cubemaps[i].texture;
3187 if (i >= MAX_CUBEMAPS)
3188 return r_texture_whitecube;
3190 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
3191 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3192 if (!cubemaps[i].texture)
3193 cubemaps[i].texture = r_texture_whitecube;
3194 return cubemaps[i].texture;
3197 void R_Shadow_FreeCubemaps(void)
3200 R_FreeTexturePool(&r_shadow_filters_texturepool);
3203 dlight_t *R_Shadow_NewWorldLight(void)
3206 light = (dlight_t *)Mem_Alloc(r_main_mempool, sizeof(dlight_t));
3207 light->next = r_shadow_worldlightchain;
3208 r_shadow_worldlightchain = light;
3212 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)
3215 // validate parameters
3216 if (style < 0 || style >= MAX_LIGHTSTYLES)
3218 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3224 // copy to light properties
3225 VectorCopy(origin, light->origin);
3226 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3227 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3228 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3229 light->color[0] = max(color[0], 0);
3230 light->color[1] = max(color[1], 0);
3231 light->color[2] = max(color[2], 0);
3232 light->radius = max(radius, 0);
3233 light->style = style;
3234 light->shadow = shadowenable;
3235 light->corona = corona;
3236 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3237 light->coronasizescale = coronasizescale;
3238 light->ambientscale = ambientscale;
3239 light->diffusescale = diffusescale;
3240 light->specularscale = specularscale;
3241 light->flags = flags;
3243 // update renderable light data
3244 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
3245 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);
3248 void R_Shadow_FreeWorldLight(dlight_t *light)
3250 dlight_t **lightpointer;
3251 R_RTLight_Uncompile(&light->rtlight);
3252 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3253 if (*lightpointer != light)
3254 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
3255 *lightpointer = light->next;
3259 void R_Shadow_ClearWorldLights(void)
3261 while (r_shadow_worldlightchain)
3262 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3263 r_shadow_selectedlight = NULL;
3264 R_Shadow_FreeCubemaps();
3267 void R_Shadow_SelectLight(dlight_t *light)
3269 if (r_shadow_selectedlight)
3270 r_shadow_selectedlight->selected = false;
3271 r_shadow_selectedlight = light;
3272 if (r_shadow_selectedlight)
3273 r_shadow_selectedlight->selected = true;
3276 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3278 // this is never batched (there can be only one)
3279 float scale = r_editlights_cursorgrid.value * 0.5f;
3280 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[1]->tex, NULL, false, false, r_editlights_cursorlocation, r_view.right, r_view.up, scale, -scale, -scale, scale, 1, 1, 1, 0.5f);
3283 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3285 // this is never batched (due to the ent parameter changing every time)
3286 // so numsurfaces == 1 and surfacelist[0] == lightnumber
3288 const dlight_t *light = (dlight_t *)ent;
3290 if (light->selected)
3291 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3294 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[surfacelist[0]]->tex, NULL, false, false, light->origin, r_view.right, r_view.up, 8, -8, -8, 8, intensity, intensity, intensity, 0.5f);
3297 void R_Shadow_DrawLightSprites(void)
3302 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3303 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 1+(i % 5), &light->rtlight);
3304 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
3307 void R_Shadow_SelectLightInView(void)
3309 float bestrating, rating, temp[3];
3310 dlight_t *best, *light;
3313 for (light = r_shadow_worldlightchain;light;light = light->next)
3315 VectorSubtract(light->origin, r_view.origin, temp);
3316 rating = (DotProduct(temp, r_view.forward) / sqrt(DotProduct(temp, temp)));
3319 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3320 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)
3322 bestrating = rating;
3327 R_Shadow_SelectLight(best);
3330 void R_Shadow_LoadWorldLights(void)
3332 int n, a, style, shadow, flags;
3333 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3334 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3335 if (r_refdef.worldmodel == NULL)
3337 Con_Print("No map loaded.\n");
3340 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3341 strlcat (name, ".rtlights", sizeof (name));
3342 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3352 for (;COM_Parse(t, true) && strcmp(
3353 if (COM_Parse(t, true))
3355 if (com_token[0] == '!')
3358 origin[0] = atof(com_token+1);
3361 origin[0] = atof(com_token);
3366 while (*s && *s != '\n' && *s != '\r')
3372 // check for modifier flags
3379 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);
3382 flags = LIGHTFLAG_REALTIMEMODE;
3390 coronasizescale = 0.25f;
3392 VectorClear(angles);
3395 if (a < 9 || !strcmp(cubemapname, "\"\""))
3397 // remove quotes on cubemapname
3398 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3401 namelen = strlen(cubemapname) - 2;
3402 memmove(cubemapname, cubemapname + 1, namelen);
3403 cubemapname[namelen] = '\0';
3407 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);
3410 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3418 Con_Printf("invalid rtlights file \"%s\"\n", name);
3419 Mem_Free(lightsstring);
3423 void R_Shadow_SaveWorldLights(void)
3426 size_t bufchars, bufmaxchars;
3428 char name[MAX_QPATH];
3429 char line[MAX_INPUTLINE];
3430 if (!r_shadow_worldlightchain)
3432 if (r_refdef.worldmodel == NULL)
3434 Con_Print("No map loaded.\n");
3437 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3438 strlcat (name, ".rtlights", sizeof (name));
3439 bufchars = bufmaxchars = 0;
3441 for (light = r_shadow_worldlightchain;light;light = light->next)
3443 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3444 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);
3445 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3446 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]);
3448 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);
3449 if (bufchars + strlen(line) > bufmaxchars)
3451 bufmaxchars = bufchars + strlen(line) + 2048;
3453 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3457 memcpy(buf, oldbuf, bufchars);
3463 memcpy(buf + bufchars, line, strlen(line));
3464 bufchars += strlen(line);
3468 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3473 void R_Shadow_LoadLightsFile(void)
3476 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3477 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3478 if (r_refdef.worldmodel == NULL)
3480 Con_Print("No map loaded.\n");
3483 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3484 strlcat (name, ".lights", sizeof (name));
3485 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3493 while (*s && *s != '\n' && *s != '\r')
3499 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);
3503 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);
3506 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3507 radius = bound(15, radius, 4096);
3508 VectorScale(color, (2.0f / (8388608.0f)), color);
3509 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3517 Con_Printf("invalid lights file \"%s\"\n", name);
3518 Mem_Free(lightsstring);
3522 // tyrlite/hmap2 light types in the delay field
3523 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3525 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3527 int entnum, style, islight, skin, pflags, effects, type, n;
3530 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3531 char key[256], value[MAX_INPUTLINE];
3533 if (r_refdef.worldmodel == NULL)
3535 Con_Print("No map loaded.\n");
3538 // try to load a .ent file first
3539 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3540 strlcat (key, ".ent", sizeof (key));
3541 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3542 // and if that is not found, fall back to the bsp file entity string
3544 data = r_refdef.worldmodel->brush.entities;
3547 for (entnum = 0;COM_ParseTokenConsole(&data) && com_token[0] == '{';entnum++)
3549 type = LIGHTTYPE_MINUSX;
3550 origin[0] = origin[1] = origin[2] = 0;
3551 originhack[0] = originhack[1] = originhack[2] = 0;
3552 angles[0] = angles[1] = angles[2] = 0;
3553 color[0] = color[1] = color[2] = 1;
3554 light[0] = light[1] = light[2] = 1;light[3] = 300;
3555 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3565 if (!COM_ParseTokenConsole(&data))
3567 if (com_token[0] == '}')
3568 break; // end of entity
3569 if (com_token[0] == '_')
3570 strlcpy(key, com_token + 1, sizeof(key));
3572 strlcpy(key, com_token, sizeof(key));
3573 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3574 key[strlen(key)-1] = 0;
3575 if (!COM_ParseTokenConsole(&data))
3577 strlcpy(value, com_token, sizeof(value));
3579 // now that we have the key pair worked out...
3580 if (!strcmp("light", key))
3582 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3586 light[0] = vec[0] * (1.0f / 256.0f);
3587 light[1] = vec[0] * (1.0f / 256.0f);
3588 light[2] = vec[0] * (1.0f / 256.0f);
3594 light[0] = vec[0] * (1.0f / 255.0f);
3595 light[1] = vec[1] * (1.0f / 255.0f);
3596 light[2] = vec[2] * (1.0f / 255.0f);
3600 else if (!strcmp("delay", key))
3602 else if (!strcmp("origin", key))
3603 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3604 else if (!strcmp("angle", key))
3605 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3606 else if (!strcmp("angles", key))
3607 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3608 else if (!strcmp("color", key))
3609 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3610 else if (!strcmp("wait", key))
3611 fadescale = atof(value);
3612 else if (!strcmp("classname", key))
3614 if (!strncmp(value, "light", 5))
3617 if (!strcmp(value, "light_fluoro"))
3622 overridecolor[0] = 1;
3623 overridecolor[1] = 1;
3624 overridecolor[2] = 1;
3626 if (!strcmp(value, "light_fluorospark"))
3631 overridecolor[0] = 1;
3632 overridecolor[1] = 1;
3633 overridecolor[2] = 1;
3635 if (!strcmp(value, "light_globe"))
3640 overridecolor[0] = 1;
3641 overridecolor[1] = 0.8;
3642 overridecolor[2] = 0.4;
3644 if (!strcmp(value, "light_flame_large_yellow"))
3649 overridecolor[0] = 1;
3650 overridecolor[1] = 0.5;
3651 overridecolor[2] = 0.1;
3653 if (!strcmp(value, "light_flame_small_yellow"))
3658 overridecolor[0] = 1;
3659 overridecolor[1] = 0.5;
3660 overridecolor[2] = 0.1;
3662 if (!strcmp(value, "light_torch_small_white"))
3667 overridecolor[0] = 1;
3668 overridecolor[1] = 0.5;
3669 overridecolor[2] = 0.1;
3671 if (!strcmp(value, "light_torch_small_walltorch"))
3676 overridecolor[0] = 1;
3677 overridecolor[1] = 0.5;
3678 overridecolor[2] = 0.1;
3682 else if (!strcmp("style", key))
3683 style = atoi(value);
3684 else if (!strcmp("skin", key))
3685 skin = (int)atof(value);
3686 else if (!strcmp("pflags", key))
3687 pflags = (int)atof(value);
3688 else if (!strcmp("effects", key))
3689 effects = (int)atof(value);
3690 else if (r_refdef.worldmodel->type == mod_brushq3)
3692 if (!strcmp("scale", key))
3693 lightscale = atof(value);
3694 if (!strcmp("fade", key))
3695 fadescale = atof(value);
3700 if (lightscale <= 0)
3704 if (color[0] == color[1] && color[0] == color[2])
3706 color[0] *= overridecolor[0];
3707 color[1] *= overridecolor[1];
3708 color[2] *= overridecolor[2];
3710 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3711 color[0] = color[0] * light[0];
3712 color[1] = color[1] * light[1];
3713 color[2] = color[2] * light[2];
3716 case LIGHTTYPE_MINUSX:
3718 case LIGHTTYPE_RECIPX:
3720 VectorScale(color, (1.0f / 16.0f), color);
3722 case LIGHTTYPE_RECIPXX:
3724 VectorScale(color, (1.0f / 16.0f), color);
3727 case LIGHTTYPE_NONE:
3731 case LIGHTTYPE_MINUSXX:
3734 VectorAdd(origin, originhack, origin);
3736 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);
3739 Mem_Free(entfiledata);
3743 void R_Shadow_SetCursorLocationForView(void)
3746 vec3_t dest, endpos;
3748 VectorMA(r_view.origin, r_editlights_cursordistance.value, r_view.forward, dest);
3749 trace = CL_Move(r_view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
3750 if (trace.fraction < 1)
3752 dist = trace.fraction * r_editlights_cursordistance.value;
3753 push = r_editlights_cursorpushback.value;
3757 VectorMA(trace.endpos, push, r_view.forward, endpos);
3758 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3762 VectorClear( endpos );
3764 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3765 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3766 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3769 void R_Shadow_UpdateWorldLightSelection(void)
3771 if (r_editlights.integer)
3773 R_Shadow_SetCursorLocationForView();
3774 R_Shadow_SelectLightInView();
3777 R_Shadow_SelectLight(NULL);
3780 void R_Shadow_EditLights_Clear_f(void)
3782 R_Shadow_ClearWorldLights();
3785 void R_Shadow_EditLights_Reload_f(void)
3787 if (!r_refdef.worldmodel)
3789 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3790 R_Shadow_ClearWorldLights();
3791 R_Shadow_LoadWorldLights();
3792 if (r_shadow_worldlightchain == NULL)
3794 R_Shadow_LoadLightsFile();
3795 if (r_shadow_worldlightchain == NULL)
3796 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3800 void R_Shadow_EditLights_Save_f(void)
3802 if (!r_refdef.worldmodel)
3804 R_Shadow_SaveWorldLights();
3807 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3809 R_Shadow_ClearWorldLights();
3810 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3813 void R_Shadow_EditLights_ImportLightsFile_f(void)
3815 R_Shadow_ClearWorldLights();
3816 R_Shadow_LoadLightsFile();
3819 void R_Shadow_EditLights_Spawn_f(void)
3822 if (!r_editlights.integer)
3824 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3827 if (Cmd_Argc() != 1)
3829 Con_Print("r_editlights_spawn does not take parameters\n");
3832 color[0] = color[1] = color[2] = 1;
3833 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3836 void R_Shadow_EditLights_Edit_f(void)
3838 vec3_t origin, angles, color;
3839 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3840 int style, shadows, flags, normalmode, realtimemode;
3841 char cubemapname[MAX_INPUTLINE];
3842 if (!r_editlights.integer)
3844 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3847 if (!r_shadow_selectedlight)
3849 Con_Print("No selected light.\n");
3852 VectorCopy(r_shadow_selectedlight->origin, origin);
3853 VectorCopy(r_shadow_selectedlight->angles, angles);
3854 VectorCopy(r_shadow_selectedlight->color, color);
3855 radius = r_shadow_selectedlight->radius;
3856 style = r_shadow_selectedlight->style;
3857 if (r_shadow_selectedlight->cubemapname)
3858 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3861 shadows = r_shadow_selectedlight->shadow;
3862 corona = r_shadow_selectedlight->corona;
3863 coronasizescale = r_shadow_selectedlight->coronasizescale;
3864 ambientscale = r_shadow_selectedlight->ambientscale;
3865 diffusescale = r_shadow_selectedlight->diffusescale;
3866 specularscale = r_shadow_selectedlight->specularscale;
3867 flags = r_shadow_selectedlight->flags;
3868 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3869 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3870 if (!strcmp(Cmd_Argv(1), "origin"))
3872 if (Cmd_Argc() != 5)
3874 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3877 origin[0] = atof(Cmd_Argv(2));
3878 origin[1] = atof(Cmd_Argv(3));
3879 origin[2] = atof(Cmd_Argv(4));
3881 else if (!strcmp(Cmd_Argv(1), "originx"))
3883 if (Cmd_Argc() != 3)
3885 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3888 origin[0] = atof(Cmd_Argv(2));
3890 else if (!strcmp(Cmd_Argv(1), "originy"))
3892 if (Cmd_Argc() != 3)
3894 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3897 origin[1] = atof(Cmd_Argv(2));
3899 else if (!strcmp(Cmd_Argv(1), "originz"))
3901 if (Cmd_Argc() != 3)
3903 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3906 origin[2] = atof(Cmd_Argv(2));
3908 else if (!strcmp(Cmd_Argv(1), "move"))
3910 if (Cmd_Argc() != 5)
3912 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3915 origin[0] += atof(Cmd_Argv(2));
3916 origin[1] += atof(Cmd_Argv(3));
3917 origin[2] += atof(Cmd_Argv(4));
3919 else if (!strcmp(Cmd_Argv(1), "movex"))
3921 if (Cmd_Argc() != 3)
3923 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3926 origin[0] += atof(Cmd_Argv(2));
3928 else if (!strcmp(Cmd_Argv(1), "movey"))
3930 if (Cmd_Argc() != 3)
3932 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3935 origin[1] += atof(Cmd_Argv(2));
3937 else if (!strcmp(Cmd_Argv(1), "movez"))
3939 if (Cmd_Argc() != 3)
3941 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3944 origin[2] += atof(Cmd_Argv(2));
3946 else if (!strcmp(Cmd_Argv(1), "angles"))
3948 if (Cmd_Argc() != 5)
3950 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3953 angles[0] = atof(Cmd_Argv(2));
3954 angles[1] = atof(Cmd_Argv(3));
3955 angles[2] = atof(Cmd_Argv(4));
3957 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3959 if (Cmd_Argc() != 3)
3961 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3964 angles[0] = atof(Cmd_Argv(2));
3966 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3968 if (Cmd_Argc() != 3)
3970 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3973 angles[1] = atof(Cmd_Argv(2));
3975 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3977 if (Cmd_Argc() != 3)
3979 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3982 angles[2] = atof(Cmd_Argv(2));
3984 else if (!strcmp(Cmd_Argv(1), "color"))
3986 if (Cmd_Argc() != 5)
3988 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3991 color[0] = atof(Cmd_Argv(2));
3992 color[1] = atof(Cmd_Argv(3));
3993 color[2] = atof(Cmd_Argv(4));
3995 else if (!strcmp(Cmd_Argv(1), "radius"))
3997 if (Cmd_Argc() != 3)
3999 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4002 radius = atof(Cmd_Argv(2));
4004 else if (!strcmp(Cmd_Argv(1), "colorscale"))
4006 if (Cmd_Argc() == 3)
4008 double scale = atof(Cmd_Argv(2));
4015 if (Cmd_Argc() != 5)
4017 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
4020 color[0] *= atof(Cmd_Argv(2));
4021 color[1] *= atof(Cmd_Argv(3));
4022 color[2] *= atof(Cmd_Argv(4));
4025 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
4027 if (Cmd_Argc() != 3)
4029 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4032 radius *= atof(Cmd_Argv(2));
4034 else if (!strcmp(Cmd_Argv(1), "style"))
4036 if (Cmd_Argc() != 3)
4038 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4041 style = atoi(Cmd_Argv(2));
4043 else if (!strcmp(Cmd_Argv(1), "cubemap"))
4047 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4050 if (Cmd_Argc() == 3)
4051 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
4055 else if (!strcmp(Cmd_Argv(1), "shadows"))
4057 if (Cmd_Argc() != 3)
4059 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4062 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4064 else if (!strcmp(Cmd_Argv(1), "corona"))
4066 if (Cmd_Argc() != 3)
4068 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4071 corona = atof(Cmd_Argv(2));
4073 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4075 if (Cmd_Argc() != 3)
4077 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4080 coronasizescale = atof(Cmd_Argv(2));
4082 else if (!strcmp(Cmd_Argv(1), "ambient"))
4084 if (Cmd_Argc() != 3)
4086 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4089 ambientscale = atof(Cmd_Argv(2));
4091 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4093 if (Cmd_Argc() != 3)
4095 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4098 diffusescale = atof(Cmd_Argv(2));
4100 else if (!strcmp(Cmd_Argv(1), "specular"))
4102 if (Cmd_Argc() != 3)
4104 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4107 specularscale = atof(Cmd_Argv(2));
4109 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4111 if (Cmd_Argc() != 3)
4113 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4116 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4118 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4120 if (Cmd_Argc() != 3)
4122 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4125 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4129 Con_Print("usage: r_editlights_edit [property] [value]\n");
4130 Con_Print("Selected light's properties:\n");
4131 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4132 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4133 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4134 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4135 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4136 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4137 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4138 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4139 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4140 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4141 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4142 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4143 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4144 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4147 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4148 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4151 void R_Shadow_EditLights_EditAll_f(void)
4155 if (!r_editlights.integer)
4157 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4161 for (light = r_shadow_worldlightchain;light;light = light->next)
4163 R_Shadow_SelectLight(light);
4164 R_Shadow_EditLights_Edit_f();
4168 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4170 int lightnumber, lightcount;
4174 if (!r_editlights.integer)
4180 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4181 if (light == r_shadow_selectedlight)
4182 lightnumber = lightcount;
4183 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;
4184 if (r_shadow_selectedlight == NULL)
4186 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4187 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;
4188 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;
4189 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;
4190 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4191 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4192 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4193 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;
4194 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4195 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4196 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4197 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4198 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
4199 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;
4200 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;
4203 void R_Shadow_EditLights_ToggleShadow_f(void)
4205 if (!r_editlights.integer)
4207 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4210 if (!r_shadow_selectedlight)
4212 Con_Print("No selected light.\n");
4215 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);
4218 void R_Shadow_EditLights_ToggleCorona_f(void)
4220 if (!r_editlights.integer)
4222 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4225 if (!r_shadow_selectedlight)
4227 Con_Print("No selected light.\n");
4230 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);
4233 void R_Shadow_EditLights_Remove_f(void)
4235 if (!r_editlights.integer)
4237 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4240 if (!r_shadow_selectedlight)
4242 Con_Print("No selected light.\n");
4245 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4246 r_shadow_selectedlight = NULL;
4249 void R_Shadow_EditLights_Help_f(void)
4252 "Documentation on r_editlights system:\n"
4254 "r_editlights : enable/disable editing mode\n"
4255 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4256 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4257 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4258 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4259 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4261 "r_editlights_help : this help\n"
4262 "r_editlights_clear : remove all lights\n"
4263 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4264 "r_editlights_save : save to .rtlights file\n"
4265 "r_editlights_spawn : create a light with default settings\n"
4266 "r_editlights_edit command : edit selected light - more documentation below\n"
4267 "r_editlights_remove : remove selected light\n"
4268 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4269 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4270 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4272 "origin x y z : set light location\n"
4273 "originx x: set x component of light location\n"
4274 "originy y: set y component of light location\n"
4275 "originz z: set z component of light location\n"
4276 "move x y z : adjust light location\n"
4277 "movex x: adjust x component of light location\n"
4278 "movey y: adjust y component of light location\n"
4279 "movez z: adjust z component of light location\n"
4280 "angles x y z : set light angles\n"
4281 "anglesx x: set x component of light angles\n"
4282 "anglesy y: set y component of light angles\n"
4283 "anglesz z: set z component of light angles\n"
4284 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4285 "radius radius : set radius (size) of light\n"
4286 "colorscale grey : multiply color of light (1 does nothing)\n"
4287 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4288 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4289 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4290 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4291 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4292 "shadows 1/0 : turn on/off shadows\n"
4293 "corona n : set corona intensity\n"
4294 "coronasize n : set corona size (0-1)\n"
4295 "ambient n : set ambient intensity (0-1)\n"
4296 "diffuse n : set diffuse intensity (0-1)\n"
4297 "specular n : set specular intensity (0-1)\n"
4298 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4299 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4300 "<nothing> : print light properties to console\n"
4304 void R_Shadow_EditLights_CopyInfo_f(void)
4306 if (!r_editlights.integer)
4308 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4311 if (!r_shadow_selectedlight)
4313 Con_Print("No selected light.\n");
4316 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4317 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4318 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4319 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4320 if (r_shadow_selectedlight->cubemapname)
4321 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
4323 r_shadow_bufferlight.cubemapname[0] = 0;
4324 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4325 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4326 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4327 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4328 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4329 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4330 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4333 void R_Shadow_EditLights_PasteInfo_f(void)
4335 if (!r_editlights.integer)
4337 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4340 if (!r_shadow_selectedlight)
4342 Con_Print("No selected light.\n");
4345 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);
4348 void R_Shadow_EditLights_Init(void)
4350 Cvar_RegisterVariable(&r_editlights);
4351 Cvar_RegisterVariable(&r_editlights_cursordistance);
4352 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4353 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4354 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4355 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4356 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
4357 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
4358 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)");
4359 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
4360 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
4361 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
4362 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)");
4363 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
4364 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
4365 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
4366 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
4367 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
4368 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
4369 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)");