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 rtexturepool_t *r_shadow_texturepool;
194 rtexture_t *r_shadow_attenuationgradienttexture;
195 rtexture_t *r_shadow_attenuation2dtexture;
196 rtexture_t *r_shadow_attenuation3dtexture;
198 // lights are reloaded when this changes
199 char r_shadow_mapname[MAX_QPATH];
201 // used only for light filters (cubemaps)
202 rtexturepool_t *r_shadow_filters_texturepool;
204 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"};
205 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"};
206 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
207 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
208 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)"};
209 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"};
210 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
211 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
212 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
213 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
214 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
215 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
216 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
217 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
218 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)"};
219 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
220 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
221 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
222 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
223 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)"};
224 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"};
225 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
226 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
227 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"};
228 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
229 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
230 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)"};
231 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
232 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
233 cvar_t r_shadow_polygonoffset = {0, "r_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)"};
234 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)"};
235 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
236 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
237 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
238 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
239 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
240 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
241 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
242 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
244 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
245 #define ATTENTABLESIZE 256
246 // 1D gradient, 2D circle and 3D sphere attenuation textures
247 #define ATTEN1DSIZE 32
248 #define ATTEN2DSIZE 64
249 #define ATTEN3DSIZE 32
251 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
252 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
253 static float r_shadow_attentable[ATTENTABLESIZE+1];
255 rtlight_t *r_shadow_compilingrtlight;
256 dlight_t *r_shadow_worldlightchain;
257 dlight_t *r_shadow_selectedlight;
258 dlight_t r_shadow_bufferlight;
259 vec3_t r_editlights_cursorlocation;
261 extern int con_vislines;
263 typedef struct cubemapinfo_s
270 #define MAX_CUBEMAPS 256
271 static int numcubemaps;
272 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
274 void R_Shadow_UncompileWorldLights(void);
275 void R_Shadow_ClearWorldLights(void);
276 void R_Shadow_SaveWorldLights(void);
277 void R_Shadow_LoadWorldLights(void);
278 void R_Shadow_LoadLightsFile(void);
279 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
280 void R_Shadow_EditLights_Reload_f(void);
281 void R_Shadow_ValidateCvars(void);
282 static void R_Shadow_MakeTextures(void);
284 // VorteX: custom editor light sprites
285 #define EDLIGHTSPRSIZE 8
286 #define EDLIGHTSELECTSPRSIZE 12
287 cachepic_t *r_editlights_sprcursor;
288 cachepic_t *r_editlights_sprlight;
289 cachepic_t *r_editlights_sprnoshadowlight;
290 cachepic_t *r_editlights_sprcubemap;
291 cachepic_t *r_editlights_sprselection;
293 void r_shadow_start(void)
295 // allocate vertex processing arrays
297 r_shadow_attenuationgradienttexture = NULL;
298 r_shadow_attenuation2dtexture = NULL;
299 r_shadow_attenuation3dtexture = NULL;
300 r_shadow_texturepool = NULL;
301 r_shadow_filters_texturepool = NULL;
302 R_Shadow_ValidateCvars();
303 R_Shadow_MakeTextures();
304 maxshadowtriangles = 0;
305 shadowelements = NULL;
306 maxshadowvertices = 0;
307 shadowvertex3f = NULL;
315 shadowmarklist = NULL;
317 r_shadow_buffer_numleafpvsbytes = 0;
318 r_shadow_buffer_leafpvs = NULL;
319 r_shadow_buffer_leaflist = NULL;
320 r_shadow_buffer_numsurfacepvsbytes = 0;
321 r_shadow_buffer_surfacepvs = NULL;
322 r_shadow_buffer_surfacelist = NULL;
323 r_shadow_buffer_numshadowtrispvsbytes = 0;
324 r_shadow_buffer_shadowtrispvs = NULL;
325 r_shadow_buffer_numlighttrispvsbytes = 0;
326 r_shadow_buffer_lighttrispvs = NULL;
329 void r_shadow_shutdown(void)
331 R_Shadow_UncompileWorldLights();
333 r_shadow_attenuationgradienttexture = NULL;
334 r_shadow_attenuation2dtexture = NULL;
335 r_shadow_attenuation3dtexture = NULL;
336 R_FreeTexturePool(&r_shadow_texturepool);
337 R_FreeTexturePool(&r_shadow_filters_texturepool);
338 maxshadowtriangles = 0;
340 Mem_Free(shadowelements);
341 shadowelements = NULL;
343 Mem_Free(shadowvertex3f);
344 shadowvertex3f = NULL;
347 Mem_Free(vertexupdate);
350 Mem_Free(vertexremap);
356 Mem_Free(shadowmark);
359 Mem_Free(shadowmarklist);
360 shadowmarklist = NULL;
362 r_shadow_buffer_numleafpvsbytes = 0;
363 if (r_shadow_buffer_leafpvs)
364 Mem_Free(r_shadow_buffer_leafpvs);
365 r_shadow_buffer_leafpvs = NULL;
366 if (r_shadow_buffer_leaflist)
367 Mem_Free(r_shadow_buffer_leaflist);
368 r_shadow_buffer_leaflist = NULL;
369 r_shadow_buffer_numsurfacepvsbytes = 0;
370 if (r_shadow_buffer_surfacepvs)
371 Mem_Free(r_shadow_buffer_surfacepvs);
372 r_shadow_buffer_surfacepvs = NULL;
373 if (r_shadow_buffer_surfacelist)
374 Mem_Free(r_shadow_buffer_surfacelist);
375 r_shadow_buffer_surfacelist = NULL;
376 r_shadow_buffer_numshadowtrispvsbytes = 0;
377 if (r_shadow_buffer_shadowtrispvs)
378 Mem_Free(r_shadow_buffer_shadowtrispvs);
379 r_shadow_buffer_numlighttrispvsbytes = 0;
380 if (r_shadow_buffer_lighttrispvs)
381 Mem_Free(r_shadow_buffer_lighttrispvs);
384 void r_shadow_newmap(void)
388 void R_Shadow_Help_f(void)
391 "Documentation on r_shadow system:\n"
393 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
394 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
395 "r_shadow_debuglight : render only this light number (-1 = all)\n"
396 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
397 "r_shadow_gloss2intensity : brightness of forced gloss\n"
398 "r_shadow_glossintensity : brightness of textured gloss\n"
399 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
400 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
401 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
402 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
403 "r_shadow_portallight : use portal visibility for static light precomputation\n"
404 "r_shadow_projectdistance : shadow volume projection distance\n"
405 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
406 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
407 "r_shadow_realtime_world : use high quality world lighting mode\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_polygonfactor : nudge shadow volumes closer/further\n"
414 "r_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_lightmaps);
446 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
447 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
448 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
449 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
450 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
451 Cvar_RegisterVariable(&r_shadow_scissor);
452 Cvar_RegisterVariable(&r_shadow_culltriangles);
453 Cvar_RegisterVariable(&r_shadow_polygonfactor);
454 Cvar_RegisterVariable(&r_shadow_polygonoffset);
455 Cvar_RegisterVariable(&r_shadow_texture3d);
456 Cvar_RegisterVariable(&gl_ext_separatestencil);
457 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
458 if (gamemode == GAME_TENEBRAE)
460 Cvar_SetValue("r_shadow_gloss", 2);
461 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
463 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
464 R_Shadow_EditLights_Init();
465 r_shadow_worldlightchain = NULL;
466 maxshadowtriangles = 0;
467 shadowelements = NULL;
468 maxshadowvertices = 0;
469 shadowvertex3f = NULL;
477 shadowmarklist = NULL;
479 r_shadow_buffer_numleafpvsbytes = 0;
480 r_shadow_buffer_leafpvs = NULL;
481 r_shadow_buffer_leaflist = NULL;
482 r_shadow_buffer_numsurfacepvsbytes = 0;
483 r_shadow_buffer_surfacepvs = NULL;
484 r_shadow_buffer_surfacelist = NULL;
485 r_shadow_buffer_shadowtrispvs = NULL;
486 r_shadow_buffer_lighttrispvs = NULL;
487 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
490 matrix4x4_t matrix_attenuationxyz =
493 {0.5, 0.0, 0.0, 0.5},
494 {0.0, 0.5, 0.0, 0.5},
495 {0.0, 0.0, 0.5, 0.5},
500 matrix4x4_t matrix_attenuationz =
503 {0.0, 0.0, 0.5, 0.5},
504 {0.0, 0.0, 0.0, 0.5},
505 {0.0, 0.0, 0.0, 0.5},
510 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
512 // make sure shadowelements is big enough for this volume
513 if (maxshadowtriangles < numtriangles)
515 maxshadowtriangles = numtriangles;
517 Mem_Free(shadowelements);
518 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
520 // make sure shadowvertex3f is big enough for this volume
521 if (maxshadowvertices < numvertices)
523 maxshadowvertices = numvertices;
525 Mem_Free(shadowvertex3f);
526 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
530 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
532 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
533 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
534 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
535 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
536 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
538 if (r_shadow_buffer_leafpvs)
539 Mem_Free(r_shadow_buffer_leafpvs);
540 if (r_shadow_buffer_leaflist)
541 Mem_Free(r_shadow_buffer_leaflist);
542 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
543 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
544 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
546 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
548 if (r_shadow_buffer_surfacepvs)
549 Mem_Free(r_shadow_buffer_surfacepvs);
550 if (r_shadow_buffer_surfacelist)
551 Mem_Free(r_shadow_buffer_surfacelist);
552 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
553 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
554 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
556 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
558 if (r_shadow_buffer_shadowtrispvs)
559 Mem_Free(r_shadow_buffer_shadowtrispvs);
560 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
561 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
563 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
565 if (r_shadow_buffer_lighttrispvs)
566 Mem_Free(r_shadow_buffer_lighttrispvs);
567 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
568 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
572 void R_Shadow_PrepareShadowMark(int numtris)
574 // make sure shadowmark is big enough for this volume
575 if (maxshadowmark < numtris)
577 maxshadowmark = numtris;
579 Mem_Free(shadowmark);
581 Mem_Free(shadowmarklist);
582 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
583 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
587 // if shadowmarkcount wrapped we clear the array and adjust accordingly
588 if (shadowmarkcount == 0)
591 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
596 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)
599 int outtriangles = 0, outvertices = 0;
602 float ratio, direction[3], projectvector[3];
604 if (projectdirection)
605 VectorScale(projectdirection, projectdistance, projectvector);
607 VectorClear(projectvector);
609 if (maxvertexupdate < innumvertices)
611 maxvertexupdate = innumvertices;
613 Mem_Free(vertexupdate);
615 Mem_Free(vertexremap);
616 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
617 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
621 if (vertexupdatenum == 0)
624 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
625 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
628 for (i = 0;i < numshadowmarktris;i++)
629 shadowmark[shadowmarktris[i]] = shadowmarkcount;
631 // create the vertices
632 if (projectdirection)
634 for (i = 0;i < numshadowmarktris;i++)
636 element = inelement3i + shadowmarktris[i] * 3;
637 for (j = 0;j < 3;j++)
639 if (vertexupdate[element[j]] != vertexupdatenum)
641 vertexupdate[element[j]] = vertexupdatenum;
642 vertexremap[element[j]] = outvertices;
643 vertex = invertex3f + element[j] * 3;
644 // project one copy of the vertex according to projectvector
645 VectorCopy(vertex, outvertex3f);
646 VectorAdd(vertex, projectvector, (outvertex3f + 3));
655 for (i = 0;i < numshadowmarktris;i++)
657 element = inelement3i + shadowmarktris[i] * 3;
658 for (j = 0;j < 3;j++)
660 if (vertexupdate[element[j]] != vertexupdatenum)
662 vertexupdate[element[j]] = vertexupdatenum;
663 vertexremap[element[j]] = outvertices;
664 vertex = invertex3f + element[j] * 3;
665 // project one copy of the vertex to the sphere radius of the light
666 // (FIXME: would projecting it to the light box be better?)
667 VectorSubtract(vertex, projectorigin, direction);
668 ratio = projectdistance / VectorLength(direction);
669 VectorCopy(vertex, outvertex3f);
670 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
678 if (r_shadow_frontsidecasting.integer)
680 for (i = 0;i < numshadowmarktris;i++)
682 int remappedelement[3];
684 const int *neighbortriangle;
686 markindex = shadowmarktris[i] * 3;
687 element = inelement3i + markindex;
688 neighbortriangle = inneighbor3i + markindex;
689 // output the front and back triangles
690 outelement3i[0] = vertexremap[element[0]];
691 outelement3i[1] = vertexremap[element[1]];
692 outelement3i[2] = vertexremap[element[2]];
693 outelement3i[3] = vertexremap[element[2]] + 1;
694 outelement3i[4] = vertexremap[element[1]] + 1;
695 outelement3i[5] = vertexremap[element[0]] + 1;
699 // output the sides (facing outward from this triangle)
700 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
702 remappedelement[0] = vertexremap[element[0]];
703 remappedelement[1] = vertexremap[element[1]];
704 outelement3i[0] = remappedelement[1];
705 outelement3i[1] = remappedelement[0];
706 outelement3i[2] = remappedelement[0] + 1;
707 outelement3i[3] = remappedelement[1];
708 outelement3i[4] = remappedelement[0] + 1;
709 outelement3i[5] = remappedelement[1] + 1;
714 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
716 remappedelement[1] = vertexremap[element[1]];
717 remappedelement[2] = vertexremap[element[2]];
718 outelement3i[0] = remappedelement[2];
719 outelement3i[1] = remappedelement[1];
720 outelement3i[2] = remappedelement[1] + 1;
721 outelement3i[3] = remappedelement[2];
722 outelement3i[4] = remappedelement[1] + 1;
723 outelement3i[5] = remappedelement[2] + 1;
728 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
730 remappedelement[0] = vertexremap[element[0]];
731 remappedelement[2] = vertexremap[element[2]];
732 outelement3i[0] = remappedelement[0];
733 outelement3i[1] = remappedelement[2];
734 outelement3i[2] = remappedelement[2] + 1;
735 outelement3i[3] = remappedelement[0];
736 outelement3i[4] = remappedelement[2] + 1;
737 outelement3i[5] = remappedelement[0] + 1;
746 for (i = 0;i < numshadowmarktris;i++)
748 int remappedelement[3];
750 const int *neighbortriangle;
752 markindex = shadowmarktris[i] * 3;
753 element = inelement3i + markindex;
754 neighbortriangle = inneighbor3i + markindex;
755 // output the front and back triangles
756 outelement3i[0] = vertexremap[element[2]];
757 outelement3i[1] = vertexremap[element[1]];
758 outelement3i[2] = vertexremap[element[0]];
759 outelement3i[3] = vertexremap[element[0]] + 1;
760 outelement3i[4] = vertexremap[element[1]] + 1;
761 outelement3i[5] = vertexremap[element[2]] + 1;
765 // output the sides (facing outward from this triangle)
766 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
768 remappedelement[0] = vertexremap[element[0]];
769 remappedelement[1] = vertexremap[element[1]];
770 outelement3i[0] = remappedelement[0];
771 outelement3i[1] = remappedelement[1];
772 outelement3i[2] = remappedelement[1] + 1;
773 outelement3i[3] = remappedelement[0];
774 outelement3i[4] = remappedelement[1] + 1;
775 outelement3i[5] = remappedelement[0] + 1;
780 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
782 remappedelement[1] = vertexremap[element[1]];
783 remappedelement[2] = vertexremap[element[2]];
784 outelement3i[0] = remappedelement[1];
785 outelement3i[1] = remappedelement[2];
786 outelement3i[2] = remappedelement[2] + 1;
787 outelement3i[3] = remappedelement[1];
788 outelement3i[4] = remappedelement[2] + 1;
789 outelement3i[5] = remappedelement[1] + 1;
794 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
796 remappedelement[0] = vertexremap[element[0]];
797 remappedelement[2] = vertexremap[element[2]];
798 outelement3i[0] = remappedelement[2];
799 outelement3i[1] = remappedelement[0];
800 outelement3i[2] = remappedelement[0] + 1;
801 outelement3i[3] = remappedelement[2];
802 outelement3i[4] = remappedelement[0] + 1;
803 outelement3i[5] = remappedelement[2] + 1;
811 *outnumvertices = outvertices;
815 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)
818 if (projectdistance < 0.1)
820 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
823 if (!numverts || !nummarktris)
825 // make sure shadowelements is big enough for this volume
826 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
827 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
828 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
829 r_refdef.stats.lights_dynamicshadowtriangles += tris;
830 R_Shadow_RenderVolume(outverts, tris, shadowvertex3f, shadowelements);
833 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)
839 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
841 tend = firsttriangle + numtris;
842 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
844 // surface box entirely inside light box, no box cull
845 if (projectdirection)
847 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
849 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
850 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
851 shadowmarklist[numshadowmark++] = t;
856 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
857 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
858 shadowmarklist[numshadowmark++] = t;
863 // surface box not entirely inside light box, cull each triangle
864 if (projectdirection)
866 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
868 v[0] = invertex3f + e[0] * 3;
869 v[1] = invertex3f + e[1] * 3;
870 v[2] = invertex3f + e[2] * 3;
871 TriangleNormal(v[0], v[1], v[2], normal);
872 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
873 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
874 shadowmarklist[numshadowmark++] = t;
879 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
881 v[0] = invertex3f + e[0] * 3;
882 v[1] = invertex3f + e[1] * 3;
883 v[2] = invertex3f + e[2] * 3;
884 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
885 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
886 shadowmarklist[numshadowmark++] = t;
892 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
894 if (r_shadow_compilingrtlight)
896 // if we're compiling an rtlight, capture the mesh
897 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
900 r_refdef.stats.lights_shadowtriangles += numtriangles;
902 R_Mesh_VertexPointer(vertex3f, 0, 0);
903 GL_LockArrays(0, numvertices);
904 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
906 // decrement stencil if backface is behind depthbuffer
907 GL_CullFace(r_view.cullface_front);
908 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
909 R_Mesh_Draw(0, numvertices, numtriangles, element3i, 0, 0);
910 // increment stencil if frontface is behind depthbuffer
911 GL_CullFace(r_view.cullface_back);
912 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
914 R_Mesh_Draw(0, numvertices, numtriangles, element3i, 0, 0);
919 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
921 float dist = sqrt(x*x+y*y+z*z);
922 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
923 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
924 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
927 static void R_Shadow_MakeTextures(void)
930 float intensity, dist;
932 R_FreeTexturePool(&r_shadow_texturepool);
933 r_shadow_texturepool = R_AllocTexturePool();
934 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
935 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
936 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
937 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
938 for (x = 0;x <= ATTENTABLESIZE;x++)
940 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
941 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
942 r_shadow_attentable[x] = bound(0, intensity, 1);
944 // 1D gradient texture
945 for (x = 0;x < ATTEN1DSIZE;x++)
946 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
947 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
949 for (y = 0;y < ATTEN2DSIZE;y++)
950 for (x = 0;x < ATTEN2DSIZE;x++)
951 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);
952 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
954 if (r_shadow_texture3d.integer && gl_texture3d)
956 for (z = 0;z < ATTEN3DSIZE;z++)
957 for (y = 0;y < ATTEN3DSIZE;y++)
958 for (x = 0;x < ATTEN3DSIZE;x++)
959 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));
960 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
963 r_shadow_attenuation3dtexture = NULL;
966 // Editor light sprites
967 r_editlights_sprcursor = Draw_CachePic("gfx/editlights/cursor", true);
968 r_editlights_sprlight = Draw_CachePic("gfx/editlights/light", true);
969 r_editlights_sprnoshadowlight = Draw_CachePic("gfx/editlights/noshadow", true);
970 r_editlights_sprcubemap = Draw_CachePic("gfx/editlights/cubemap", true);
971 r_editlights_sprselection = Draw_CachePic("gfx/editlights/selection", true);
974 void R_Shadow_ValidateCvars(void)
976 if (r_shadow_texture3d.integer && !gl_texture3d)
977 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
978 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
979 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
980 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
981 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
984 void R_Shadow_RenderMode_Begin(void)
986 R_Shadow_ValidateCvars();
988 if (!r_shadow_attenuation2dtexture
989 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
990 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
991 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
992 R_Shadow_MakeTextures();
995 R_Mesh_ColorPointer(NULL, 0, 0);
996 R_Mesh_ResetTextureState();
997 GL_BlendFunc(GL_ONE, GL_ZERO);
999 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1001 GL_DepthMask(false);
1002 GL_Color(0, 0, 0, 1);
1003 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1005 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1007 if (gl_ext_separatestencil.integer)
1008 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
1009 else if (gl_ext_stenciltwoside.integer)
1010 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
1012 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
1014 if (r_glsl.integer && gl_support_fragment_shader)
1015 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1016 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1017 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1019 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1022 void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
1024 rsurface.rtlight = rtlight;
1027 void R_Shadow_RenderMode_Reset(void)
1030 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1032 qglUseProgramObjectARB(0);CHECKGLERROR
1034 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1036 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1038 R_Mesh_ColorPointer(NULL, 0, 0);
1039 R_Mesh_ResetTextureState();
1040 GL_DepthRange(0, 1);
1042 GL_DepthMask(false);
1043 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1044 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1045 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1046 qglStencilMask(~0);CHECKGLERROR
1047 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1048 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1049 GL_CullFace(r_view.cullface_back);
1050 GL_Color(1, 1, 1, 1);
1051 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
1052 GL_BlendFunc(GL_ONE, GL_ZERO);
1055 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean clearstencil)
1058 R_Shadow_RenderMode_Reset();
1059 GL_ColorMask(0, 0, 0, 0);
1060 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1061 qglDepthFunc(GL_LESS);CHECKGLERROR
1062 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1063 r_shadow_rendermode = r_shadow_shadowingrendermode;
1064 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SEPARATESTENCIL)
1066 GL_CullFace(GL_NONE);
1067 qglStencilOpSeparate(r_view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1068 qglStencilOpSeparate(r_view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1070 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1072 GL_CullFace(GL_NONE);
1073 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1074 qglActiveStencilFaceEXT(r_view.cullface_front);CHECKGLERROR
1075 qglStencilMask(~0);CHECKGLERROR
1076 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1077 qglActiveStencilFaceEXT(r_view.cullface_back);CHECKGLERROR
1078 qglStencilMask(~0);CHECKGLERROR
1079 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1082 GL_Clear(GL_STENCIL_BUFFER_BIT);
1083 r_refdef.stats.lights_clears++;
1086 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
1089 R_Shadow_RenderMode_Reset();
1090 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1093 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1097 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1098 // only draw light where this geometry was already rendered AND the
1099 // stencil is 128 (values other than this mean shadow)
1100 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1102 r_shadow_rendermode = r_shadow_lightingrendermode;
1103 // do global setup needed for the chosen lighting mode
1104 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1106 R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
1107 R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
1108 R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
1109 R_Mesh_TexBindCubeMap(3, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
1110 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
1111 R_Mesh_TexBind(5, R_GetTexture(r_texture_white)); // pants
1112 R_Mesh_TexBind(6, R_GetTexture(r_texture_white)); // shirt
1113 R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); // lightmap
1114 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); // deluxemap
1115 R_Mesh_TexBind(9, R_GetTexture(r_texture_black)); // glow
1116 //R_Mesh_TexMatrix(3, rsurface.entitytolight); // light filter matrix
1117 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1118 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1123 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1126 R_Shadow_RenderMode_Reset();
1127 GL_BlendFunc(GL_ONE, GL_ONE);
1128 GL_DepthRange(0, 1);
1129 GL_DepthTest(r_showshadowvolumes.integer < 2);
1130 GL_Color(0.0, 0.0125 * r_view.colorscale, 0.1 * r_view.colorscale, 1);
1131 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1132 GL_CullFace(GL_NONE);
1133 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1136 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1139 R_Shadow_RenderMode_Reset();
1140 GL_BlendFunc(GL_ONE, GL_ONE);
1141 GL_DepthRange(0, 1);
1142 GL_DepthTest(r_showlighting.integer < 2);
1143 GL_Color(0.1 * r_view.colorscale, 0.0125 * r_view.colorscale, 0, 1);
1146 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1150 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1151 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1153 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1156 void R_Shadow_RenderMode_End(void)
1159 R_Shadow_RenderMode_Reset();
1160 R_Shadow_RenderMode_ActiveLight(NULL);
1162 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1163 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1166 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1168 int i, ix1, iy1, ix2, iy2;
1169 float x1, y1, x2, y2;
1172 mplane_t planes[11];
1173 float vertex3f[256*3];
1175 // if view is inside the light box, just say yes it's visible
1176 if (BoxesOverlap(r_view.origin, r_view.origin, mins, maxs))
1178 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1182 // create a temporary brush describing the area the light can affect in worldspace
1183 VectorNegate(r_view.frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -r_view.frustum[0].dist;
1184 VectorNegate(r_view.frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -r_view.frustum[1].dist;
1185 VectorNegate(r_view.frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -r_view.frustum[2].dist;
1186 VectorNegate(r_view.frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -r_view.frustum[3].dist;
1187 VectorNegate(r_view.frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -r_view.frustum[4].dist;
1188 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1189 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1190 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1191 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1192 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1193 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1195 // turn the brush into a mesh
1196 memset(&mesh, 0, sizeof(rmesh_t));
1197 mesh.maxvertices = 256;
1198 mesh.vertex3f = vertex3f;
1199 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1200 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1202 // if that mesh is empty, the light is not visible at all
1203 if (!mesh.numvertices)
1206 if (!r_shadow_scissor.integer)
1209 // if that mesh is not empty, check what area of the screen it covers
1210 x1 = y1 = x2 = y2 = 0;
1212 //Con_Printf("%i vertices to transform...\n", mesh.numvertices);
1213 for (i = 0;i < mesh.numvertices;i++)
1215 VectorCopy(mesh.vertex3f + i * 3, v);
1216 GL_TransformToScreen(v, v2);
1217 //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]);
1220 if (x1 > v2[0]) x1 = v2[0];
1221 if (x2 < v2[0]) x2 = v2[0];
1222 if (y1 > v2[1]) y1 = v2[1];
1223 if (y2 < v2[1]) y2 = v2[1];
1232 // now convert the scissor rectangle to integer screen coordinates
1233 ix1 = (int)(x1 - 1.0f);
1234 iy1 = (int)(y1 - 1.0f);
1235 ix2 = (int)(x2 + 1.0f);
1236 iy2 = (int)(y2 + 1.0f);
1237 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1239 // clamp it to the screen
1240 if (ix1 < r_view.x) ix1 = r_view.x;
1241 if (iy1 < r_view.y) iy1 = r_view.y;
1242 if (ix2 > r_view.x + r_view.width) ix2 = r_view.x + r_view.width;
1243 if (iy2 > r_view.y + r_view.height) iy2 = r_view.y + r_view.height;
1245 // if it is inside out, it's not visible
1246 if (ix2 <= ix1 || iy2 <= iy1)
1249 // the light area is visible, set up the scissor rectangle
1250 GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1251 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1252 //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1253 r_refdef.stats.lights_scissored++;
1257 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1259 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1260 float *normal3f = rsurface.normal3f + 3 * firstvertex;
1261 float *color4f = rsurface.array_color4f + 4 * firstvertex;
1262 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1263 if (r_textureunits.integer >= 3)
1265 if (VectorLength2(diffusecolor) > 0)
1267 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1269 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1270 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1271 if ((dot = DotProduct(n, v)) < 0)
1273 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1274 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1277 VectorCopy(ambientcolor, color4f);
1278 if (r_refdef.fogenabled)
1281 f = FogPoint_Model(vertex3f);
1282 VectorScale(color4f, f, color4f);
1289 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1291 VectorCopy(ambientcolor, color4f);
1292 if (r_refdef.fogenabled)
1295 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1296 f = FogPoint_Model(vertex3f);
1297 VectorScale(color4f, f, color4f);
1303 else if (r_textureunits.integer >= 2)
1305 if (VectorLength2(diffusecolor) > 0)
1307 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1309 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1310 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1312 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1313 if ((dot = DotProduct(n, v)) < 0)
1315 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1316 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1317 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1318 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1322 color4f[0] = ambientcolor[0] * distintensity;
1323 color4f[1] = ambientcolor[1] * distintensity;
1324 color4f[2] = ambientcolor[2] * distintensity;
1326 if (r_refdef.fogenabled)
1329 f = FogPoint_Model(vertex3f);
1330 VectorScale(color4f, f, color4f);
1334 VectorClear(color4f);
1340 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1342 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1343 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1345 color4f[0] = ambientcolor[0] * distintensity;
1346 color4f[1] = ambientcolor[1] * distintensity;
1347 color4f[2] = ambientcolor[2] * distintensity;
1348 if (r_refdef.fogenabled)
1351 f = FogPoint_Model(vertex3f);
1352 VectorScale(color4f, f, color4f);
1356 VectorClear(color4f);
1363 if (VectorLength2(diffusecolor) > 0)
1365 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1367 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1368 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1370 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1371 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1372 if ((dot = DotProduct(n, v)) < 0)
1374 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1375 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1376 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1377 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1381 color4f[0] = ambientcolor[0] * distintensity;
1382 color4f[1] = ambientcolor[1] * distintensity;
1383 color4f[2] = ambientcolor[2] * distintensity;
1385 if (r_refdef.fogenabled)
1388 f = FogPoint_Model(vertex3f);
1389 VectorScale(color4f, f, color4f);
1393 VectorClear(color4f);
1399 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1401 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1402 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1404 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1405 color4f[0] = ambientcolor[0] * distintensity;
1406 color4f[1] = ambientcolor[1] * distintensity;
1407 color4f[2] = ambientcolor[2] * distintensity;
1408 if (r_refdef.fogenabled)
1411 f = FogPoint_Model(vertex3f);
1412 VectorScale(color4f, f, color4f);
1416 VectorClear(color4f);
1423 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1425 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1428 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1429 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1430 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1431 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1432 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1434 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1436 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1437 // the cubemap normalizes this for us
1438 out3f[0] = DotProduct(svector3f, lightdir);
1439 out3f[1] = DotProduct(tvector3f, lightdir);
1440 out3f[2] = DotProduct(normal3f, lightdir);
1444 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1447 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1448 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1449 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1450 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1451 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1452 float lightdir[3], eyedir[3], halfdir[3];
1453 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1455 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1456 VectorNormalize(lightdir);
1457 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
1458 VectorNormalize(eyedir);
1459 VectorAdd(lightdir, eyedir, halfdir);
1460 // the cubemap normalizes this for us
1461 out3f[0] = DotProduct(svector3f, halfdir);
1462 out3f[1] = DotProduct(tvector3f, halfdir);
1463 out3f[2] = DotProduct(normal3f, halfdir);
1467 static void R_Shadow_RenderLighting_VisibleLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
1469 // used to display how many times a surface is lit for level design purposes
1470 GL_Color(0.1 * r_view.colorscale, 0.025 * r_view.colorscale, 0, 1);
1471 R_Mesh_ColorPointer(NULL, 0, 0);
1472 R_Mesh_ResetTextureState();
1473 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1476 static void R_Shadow_RenderLighting_Light_GLSL(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
1478 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1479 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
1480 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
1481 R_Mesh_TexBind(0, R_GetTexture(rsurface.texture->currentskinframe->nmap));
1482 R_Mesh_TexBind(1, R_GetTexture(rsurface.texture->basetexture));
1483 R_Mesh_TexBind(2, R_GetTexture(rsurface.texture->glosstexture));
1484 R_Mesh_TexBindCubeMap(3, R_GetTexture(rsurface.rtlight->currentcubemap));
1485 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation));
1486 R_Mesh_TexBind(5, R_GetTexture(rsurface.texture->currentskinframe->pants));
1487 R_Mesh_TexBind(6, R_GetTexture(rsurface.texture->currentskinframe->shirt));
1488 R_Mesh_TexBind(10, R_GetTexture(r_shadow_attenuationgradienttexture));
1489 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
1490 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
1491 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
1492 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
1493 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1495 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1497 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1498 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1500 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1504 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)
1506 // shared final code for all the dot3 layers
1508 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1509 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1511 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1512 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1516 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)
1519 // colorscale accounts for how much we multiply the brightness
1522 // mult is how many times the final pass of the lighting will be
1523 // performed to get more brightness than otherwise possible.
1525 // Limit mult to 64 for sanity sake.
1527 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1529 // 3 3D combine path (Geforce3, Radeon 8500)
1530 memset(&m, 0, sizeof(m));
1531 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1532 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1533 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1534 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1535 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1536 m.tex[1] = R_GetTexture(basetexture);
1537 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1538 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1539 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1540 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1541 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
1542 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1543 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1544 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1545 m.texmatrix[2] = rsurface.entitytolight;
1546 GL_BlendFunc(GL_ONE, GL_ONE);
1548 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1550 // 2 3D combine path (Geforce3, original Radeon)
1551 memset(&m, 0, sizeof(m));
1552 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1553 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1554 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1555 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1556 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1557 m.tex[1] = R_GetTexture(basetexture);
1558 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1559 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1560 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1561 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1562 GL_BlendFunc(GL_ONE, GL_ONE);
1564 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1566 // 4 2D combine path (Geforce3, Radeon 8500)
1567 memset(&m, 0, sizeof(m));
1568 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1569 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1570 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1571 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1572 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1573 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1574 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1575 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1576 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1577 m.texmatrix[1] = rsurface.entitytoattenuationz;
1578 m.tex[2] = R_GetTexture(basetexture);
1579 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1580 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1581 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1582 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1583 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1585 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
1586 m.pointer_texcoord3f[3] = rsurface.vertex3f;
1587 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
1588 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
1589 m.texmatrix[3] = rsurface.entitytolight;
1591 GL_BlendFunc(GL_ONE, GL_ONE);
1593 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1595 // 3 2D combine path (Geforce3, original Radeon)
1596 memset(&m, 0, sizeof(m));
1597 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1598 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1599 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1600 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1601 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1602 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1603 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1604 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1605 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1606 m.texmatrix[1] = rsurface.entitytoattenuationz;
1607 m.tex[2] = R_GetTexture(basetexture);
1608 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1609 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1610 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1611 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1612 GL_BlendFunc(GL_ONE, GL_ONE);
1616 // 2/2/2 2D combine path (any dot3 card)
1617 memset(&m, 0, sizeof(m));
1618 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1619 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1620 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1621 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1622 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1623 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1624 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1625 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1626 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1627 m.texmatrix[1] = rsurface.entitytoattenuationz;
1628 R_Mesh_TextureState(&m);
1629 GL_ColorMask(0,0,0,1);
1630 GL_BlendFunc(GL_ONE, GL_ZERO);
1631 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1634 memset(&m, 0, sizeof(m));
1635 m.tex[0] = R_GetTexture(basetexture);
1636 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1637 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1638 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1639 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1640 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1642 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1643 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1644 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1645 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1646 m.texmatrix[1] = rsurface.entitytolight;
1648 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1650 // this final code is shared
1651 R_Mesh_TextureState(&m);
1652 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1655 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)
1658 // colorscale accounts for how much we multiply the brightness
1661 // mult is how many times the final pass of the lighting will be
1662 // performed to get more brightness than otherwise possible.
1664 // Limit mult to 64 for sanity sake.
1666 // generate normalization cubemap texcoords
1667 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1668 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1670 // 3/2 3D combine path (Geforce3, Radeon 8500)
1671 memset(&m, 0, sizeof(m));
1672 m.tex[0] = R_GetTexture(normalmaptexture);
1673 m.texcombinergb[0] = GL_REPLACE;
1674 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1675 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1676 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1677 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1678 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1679 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1680 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1681 m.pointer_texcoord_bufferobject[1] = 0;
1682 m.pointer_texcoord_bufferoffset[1] = 0;
1683 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1684 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1685 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1686 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1687 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
1688 R_Mesh_TextureState(&m);
1689 GL_ColorMask(0,0,0,1);
1690 GL_BlendFunc(GL_ONE, GL_ZERO);
1691 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1694 memset(&m, 0, sizeof(m));
1695 m.tex[0] = R_GetTexture(basetexture);
1696 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1697 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1698 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1699 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1700 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1702 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1703 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1704 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1705 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1706 m.texmatrix[1] = rsurface.entitytolight;
1708 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1710 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1712 // 1/2/2 3D combine path (original Radeon)
1713 memset(&m, 0, sizeof(m));
1714 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1715 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1716 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1717 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1718 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1719 R_Mesh_TextureState(&m);
1720 GL_ColorMask(0,0,0,1);
1721 GL_BlendFunc(GL_ONE, GL_ZERO);
1722 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1725 memset(&m, 0, sizeof(m));
1726 m.tex[0] = R_GetTexture(normalmaptexture);
1727 m.texcombinergb[0] = GL_REPLACE;
1728 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1729 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1730 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1731 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1732 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1733 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1734 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1735 m.pointer_texcoord_bufferobject[1] = 0;
1736 m.pointer_texcoord_bufferoffset[1] = 0;
1737 R_Mesh_TextureState(&m);
1738 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1739 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1742 memset(&m, 0, sizeof(m));
1743 m.tex[0] = R_GetTexture(basetexture);
1744 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1745 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1746 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1747 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1748 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1750 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1751 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1752 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1753 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1754 m.texmatrix[1] = rsurface.entitytolight;
1756 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1758 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1760 // 2/2 3D combine path (original Radeon)
1761 memset(&m, 0, sizeof(m));
1762 m.tex[0] = R_GetTexture(normalmaptexture);
1763 m.texcombinergb[0] = GL_REPLACE;
1764 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1765 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1766 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1767 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1768 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1769 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1770 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1771 m.pointer_texcoord_bufferobject[1] = 0;
1772 m.pointer_texcoord_bufferoffset[1] = 0;
1773 R_Mesh_TextureState(&m);
1774 GL_ColorMask(0,0,0,1);
1775 GL_BlendFunc(GL_ONE, GL_ZERO);
1776 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1779 memset(&m, 0, sizeof(m));
1780 m.tex[0] = R_GetTexture(basetexture);
1781 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1782 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1783 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1784 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1785 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1786 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1787 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1788 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1789 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
1790 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1792 else if (r_textureunits.integer >= 4)
1794 // 4/2 2D combine path (Geforce3, Radeon 8500)
1795 memset(&m, 0, sizeof(m));
1796 m.tex[0] = R_GetTexture(normalmaptexture);
1797 m.texcombinergb[0] = GL_REPLACE;
1798 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1799 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1800 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1801 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1802 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1803 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1804 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1805 m.pointer_texcoord_bufferobject[1] = 0;
1806 m.pointer_texcoord_bufferoffset[1] = 0;
1807 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1808 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1809 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1810 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1811 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
1812 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1813 m.pointer_texcoord3f[3] = rsurface.vertex3f;
1814 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
1815 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
1816 m.texmatrix[3] = rsurface.entitytoattenuationz;
1817 R_Mesh_TextureState(&m);
1818 GL_ColorMask(0,0,0,1);
1819 GL_BlendFunc(GL_ONE, GL_ZERO);
1820 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1823 memset(&m, 0, sizeof(m));
1824 m.tex[0] = R_GetTexture(basetexture);
1825 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1826 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1827 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1828 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1829 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1831 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1832 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1833 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1834 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1835 m.texmatrix[1] = rsurface.entitytolight;
1837 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1841 // 2/2/2 2D combine path (any dot3 card)
1842 memset(&m, 0, sizeof(m));
1843 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1844 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1845 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1846 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1847 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1848 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1849 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1850 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1851 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1852 m.texmatrix[1] = rsurface.entitytoattenuationz;
1853 R_Mesh_TextureState(&m);
1854 GL_ColorMask(0,0,0,1);
1855 GL_BlendFunc(GL_ONE, GL_ZERO);
1856 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1859 memset(&m, 0, sizeof(m));
1860 m.tex[0] = R_GetTexture(normalmaptexture);
1861 m.texcombinergb[0] = GL_REPLACE;
1862 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1863 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1864 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1865 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1866 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1867 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1868 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1869 m.pointer_texcoord_bufferobject[1] = 0;
1870 m.pointer_texcoord_bufferoffset[1] = 0;
1871 R_Mesh_TextureState(&m);
1872 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1873 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1876 memset(&m, 0, sizeof(m));
1877 m.tex[0] = R_GetTexture(basetexture);
1878 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1879 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1880 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1881 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1882 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1884 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1885 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1886 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1887 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1888 m.texmatrix[1] = rsurface.entitytolight;
1890 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1892 // this final code is shared
1893 R_Mesh_TextureState(&m);
1894 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1897 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)
1899 float glossexponent;
1901 // FIXME: detect blendsquare!
1902 //if (!gl_support_blendsquare)
1905 // generate normalization cubemap texcoords
1906 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1907 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1909 // 2/0/0/1/2 3D combine blendsquare path
1910 memset(&m, 0, sizeof(m));
1911 m.tex[0] = R_GetTexture(normalmaptexture);
1912 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1913 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1914 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1915 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1916 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1917 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1918 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1919 m.pointer_texcoord_bufferobject[1] = 0;
1920 m.pointer_texcoord_bufferoffset[1] = 0;
1921 R_Mesh_TextureState(&m);
1922 GL_ColorMask(0,0,0,1);
1923 // this squares the result
1924 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1925 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1927 // second and third pass
1928 R_Mesh_ResetTextureState();
1929 // square alpha in framebuffer a few times to make it shiny
1930 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1931 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1932 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1935 memset(&m, 0, sizeof(m));
1936 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1937 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1938 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1939 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1940 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1941 R_Mesh_TextureState(&m);
1942 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1943 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1946 memset(&m, 0, sizeof(m));
1947 m.tex[0] = R_GetTexture(glosstexture);
1948 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1949 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1950 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1951 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1952 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1954 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1955 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1956 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1957 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1958 m.texmatrix[1] = rsurface.entitytolight;
1960 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1962 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1964 // 2/0/0/2 3D combine blendsquare path
1965 memset(&m, 0, sizeof(m));
1966 m.tex[0] = R_GetTexture(normalmaptexture);
1967 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1968 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1969 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1970 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1971 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1972 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1973 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1974 m.pointer_texcoord_bufferobject[1] = 0;
1975 m.pointer_texcoord_bufferoffset[1] = 0;
1976 R_Mesh_TextureState(&m);
1977 GL_ColorMask(0,0,0,1);
1978 // this squares the result
1979 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1980 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1982 // second and third pass
1983 R_Mesh_ResetTextureState();
1984 // square alpha in framebuffer a few times to make it shiny
1985 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1986 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1987 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1990 memset(&m, 0, sizeof(m));
1991 m.tex[0] = R_GetTexture(glosstexture);
1992 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1993 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1994 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1995 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1996 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1997 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1998 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1999 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2000 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2001 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2005 // 2/0/0/2/2 2D combine blendsquare path
2006 memset(&m, 0, sizeof(m));
2007 m.tex[0] = R_GetTexture(normalmaptexture);
2008 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2009 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2010 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2011 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2012 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2013 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2014 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2015 m.pointer_texcoord_bufferobject[1] = 0;
2016 m.pointer_texcoord_bufferoffset[1] = 0;
2017 R_Mesh_TextureState(&m);
2018 GL_ColorMask(0,0,0,1);
2019 // this squares the result
2020 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2021 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2023 // second and third pass
2024 R_Mesh_ResetTextureState();
2025 // square alpha in framebuffer a few times to make it shiny
2026 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2027 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2028 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2031 memset(&m, 0, sizeof(m));
2032 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2033 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2034 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2035 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2036 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2037 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2038 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2039 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2040 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2041 m.texmatrix[1] = rsurface.entitytoattenuationz;
2042 R_Mesh_TextureState(&m);
2043 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2044 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2047 memset(&m, 0, sizeof(m));
2048 m.tex[0] = R_GetTexture(glosstexture);
2049 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2050 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2051 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2052 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2053 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2055 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2056 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2057 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2058 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2059 m.texmatrix[1] = rsurface.entitytolight;
2061 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2063 // this final code is shared
2064 R_Mesh_TextureState(&m);
2065 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
2068 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)
2070 // ARB path (any Geforce, any Radeon)
2071 qboolean doambient = ambientscale > 0;
2072 qboolean dodiffuse = diffusescale > 0;
2073 qboolean dospecular = specularscale > 0;
2074 if (!doambient && !dodiffuse && !dospecular)
2076 R_Mesh_ColorPointer(NULL, 0, 0);
2078 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, ambientscale * r_view.colorscale);
2080 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_view.colorscale);
2084 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, ambientscale * r_view.colorscale);
2086 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_view.colorscale);
2091 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, ambientscale * r_view.colorscale);
2093 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_view.colorscale);
2096 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale);
2099 void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, vec3_t diffusecolor2, vec3_t ambientcolor2)
2106 int newnumtriangles;
2110 int newelements[4096*3];
2111 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2112 for (renders = 0;renders < 64;renders++)
2117 newnumtriangles = 0;
2119 // due to low fillrate on the cards this vertex lighting path is
2120 // designed for, we manually cull all triangles that do not
2121 // contain a lit vertex
2122 // this builds batches of triangles from multiple surfaces and
2123 // renders them at once
2124 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2126 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2128 if (newnumtriangles)
2130 newfirstvertex = min(newfirstvertex, e[0]);
2131 newlastvertex = max(newlastvertex, e[0]);
2135 newfirstvertex = e[0];
2136 newlastvertex = e[0];
2138 newfirstvertex = min(newfirstvertex, e[1]);
2139 newlastvertex = max(newlastvertex, e[1]);
2140 newfirstvertex = min(newfirstvertex, e[2]);
2141 newlastvertex = max(newlastvertex, e[2]);
2147 if (newnumtriangles >= (int)(sizeof(newelements)/sizeof(float[3])))
2149 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2150 newnumtriangles = 0;
2156 if (newnumtriangles >= 1)
2158 // if all triangles are included, use the original array to take advantage of the bufferobject if possible
2159 if (newnumtriangles == numtriangles)
2160 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2162 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2165 // if we couldn't find any lit triangles, exit early
2168 // now reduce the intensity for the next overbright pass
2169 // we have to clamp to 0 here incase the drivers have improper
2170 // handling of negative colors
2171 // (some old drivers even have improper handling of >1 color)
2173 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2175 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2177 c[0] = max(0, c[0] - 1);
2178 c[1] = max(0, c[1] - 1);
2179 c[2] = max(0, c[2] - 1);
2191 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)
2193 // OpenGL 1.1 path (anything)
2194 float ambientcolorbase[3], diffusecolorbase[3];
2195 float ambientcolorpants[3], diffusecolorpants[3];
2196 float ambientcolorshirt[3], diffusecolorshirt[3];
2198 VectorScale(lightcolorbase, ambientscale * 2 * r_view.colorscale, ambientcolorbase);
2199 VectorScale(lightcolorbase, diffusescale * 2 * r_view.colorscale, diffusecolorbase);
2200 VectorScale(lightcolorpants, ambientscale * 2 * r_view.colorscale, ambientcolorpants);
2201 VectorScale(lightcolorpants, diffusescale * 2 * r_view.colorscale, diffusecolorpants);
2202 VectorScale(lightcolorshirt, ambientscale * 2 * r_view.colorscale, ambientcolorshirt);
2203 VectorScale(lightcolorshirt, diffusescale * 2 * r_view.colorscale, diffusecolorshirt);
2204 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2205 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2206 memset(&m, 0, sizeof(m));
2207 m.tex[0] = R_GetTexture(basetexture);
2208 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2209 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2210 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2211 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2212 if (r_textureunits.integer >= 2)
2215 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2216 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2217 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2218 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2219 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2220 if (r_textureunits.integer >= 3)
2222 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2223 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2224 m.texmatrix[2] = rsurface.entitytoattenuationz;
2225 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2226 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2227 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2230 R_Mesh_TextureState(&m);
2231 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2232 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorbase, ambientcolorbase);
2235 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2236 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorpants, ambientcolorpants);
2240 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2241 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorshirt, ambientcolorshirt);
2245 extern cvar_t gl_lightmaps;
2246 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset)
2248 float ambientscale, diffusescale, specularscale;
2249 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2251 // calculate colors to render this texture with
2252 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2253 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2254 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2255 ambientscale = rsurface.rtlight->ambientscale;
2256 diffusescale = rsurface.rtlight->diffusescale;
2257 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2258 if (!r_shadow_usenormalmap.integer)
2260 ambientscale += 1.0f * diffusescale;
2264 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2266 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
2267 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
2268 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
2269 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_view.cullface_back);
2270 nmap = rsurface.texture->currentskinframe->nmap;
2271 if (gl_lightmaps.integer)
2272 nmap = r_texture_blanknormalmap;
2273 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
2275 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2276 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2279 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2280 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2281 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2284 VectorClear(lightcolorpants);
2287 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2288 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2289 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2292 VectorClear(lightcolorshirt);
2293 switch (r_shadow_rendermode)
2295 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2296 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2297 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, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2299 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2300 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, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2302 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2303 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, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2305 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2306 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, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2309 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2315 switch (r_shadow_rendermode)
2317 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2318 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2319 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, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2321 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2322 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, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2324 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2325 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, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2327 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2328 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, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2331 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2337 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)
2339 matrix4x4_t tempmatrix = *matrix;
2340 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2342 // if this light has been compiled before, free the associated data
2343 R_RTLight_Uncompile(rtlight);
2345 // clear it completely to avoid any lingering data
2346 memset(rtlight, 0, sizeof(*rtlight));
2348 // copy the properties
2349 rtlight->matrix_lighttoworld = tempmatrix;
2350 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2351 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2352 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2353 VectorCopy(color, rtlight->color);
2354 rtlight->cubemapname[0] = 0;
2355 if (cubemapname && cubemapname[0])
2356 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2357 rtlight->shadow = shadow;
2358 rtlight->corona = corona;
2359 rtlight->style = style;
2360 rtlight->isstatic = isstatic;
2361 rtlight->coronasizescale = coronasizescale;
2362 rtlight->ambientscale = ambientscale;
2363 rtlight->diffusescale = diffusescale;
2364 rtlight->specularscale = specularscale;
2365 rtlight->flags = flags;
2367 // compute derived data
2368 //rtlight->cullradius = rtlight->radius;
2369 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2370 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2371 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2372 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2373 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2374 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2375 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2378 // compiles rtlight geometry
2379 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2380 void R_RTLight_Compile(rtlight_t *rtlight)
2383 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2384 int lighttris, shadowtris, shadowmeshes, shadowmeshtris;
2385 entity_render_t *ent = r_refdef.worldentity;
2386 model_t *model = r_refdef.worldmodel;
2387 unsigned char *data;
2389 // compile the light
2390 rtlight->compiled = true;
2391 rtlight->static_numleafs = 0;
2392 rtlight->static_numleafpvsbytes = 0;
2393 rtlight->static_leaflist = NULL;
2394 rtlight->static_leafpvs = NULL;
2395 rtlight->static_numsurfaces = 0;
2396 rtlight->static_surfacelist = NULL;
2397 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2398 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2399 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2400 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2401 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2402 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2404 if (model && model->GetLightInfo)
2406 // this variable must be set for the CompileShadowVolume code
2407 r_shadow_compilingrtlight = rtlight;
2408 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);
2409 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);
2410 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2411 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2412 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2413 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2414 rtlight->static_numsurfaces = numsurfaces;
2415 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2416 rtlight->static_numleafs = numleafs;
2417 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2418 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2419 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2420 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2421 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2422 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2423 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2424 if (rtlight->static_numsurfaces)
2425 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2426 if (rtlight->static_numleafs)
2427 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2428 if (rtlight->static_numleafpvsbytes)
2429 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2430 if (rtlight->static_numshadowtrispvsbytes)
2431 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2432 if (rtlight->static_numlighttrispvsbytes)
2433 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2434 if (model->CompileShadowVolume && rtlight->shadow)
2435 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2436 // now we're done compiling the rtlight
2437 r_shadow_compilingrtlight = NULL;
2441 // use smallest available cullradius - box radius or light radius
2442 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2443 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2447 if (rtlight->static_meshchain_shadow)
2450 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2453 shadowmeshtris += mesh->numtriangles;
2458 if (rtlight->static_numlighttrispvsbytes)
2459 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2460 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2464 if (rtlight->static_numlighttrispvsbytes)
2465 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2466 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2469 if (developer.integer >= 10)
2470 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);
2473 void R_RTLight_Uncompile(rtlight_t *rtlight)
2475 if (rtlight->compiled)
2477 if (rtlight->static_meshchain_shadow)
2478 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2479 rtlight->static_meshchain_shadow = NULL;
2480 // these allocations are grouped
2481 if (rtlight->static_surfacelist)
2482 Mem_Free(rtlight->static_surfacelist);
2483 rtlight->static_numleafs = 0;
2484 rtlight->static_numleafpvsbytes = 0;
2485 rtlight->static_leaflist = NULL;
2486 rtlight->static_leafpvs = NULL;
2487 rtlight->static_numsurfaces = 0;
2488 rtlight->static_surfacelist = NULL;
2489 rtlight->static_numshadowtrispvsbytes = 0;
2490 rtlight->static_shadowtrispvs = NULL;
2491 rtlight->static_numlighttrispvsbytes = 0;
2492 rtlight->static_lighttrispvs = NULL;
2493 rtlight->compiled = false;
2497 void R_Shadow_UncompileWorldLights(void)
2500 for (light = r_shadow_worldlightchain;light;light = light->next)
2501 R_RTLight_Uncompile(&light->rtlight);
2504 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2508 // reset the count of frustum planes
2509 // see rsurface.rtlight_frustumplanes definition for how much this array
2511 rsurface.rtlight_numfrustumplanes = 0;
2513 // haven't implemented a culling path for ortho rendering
2514 if (!r_view.useperspective)
2516 // check if the light is on screen and copy the 4 planes if it is
2517 for (i = 0;i < 4;i++)
2518 if (PlaneDiff(rtlight->shadoworigin, &r_view.frustum[i]) < -0.03125)
2521 for (i = 0;i < 4;i++)
2522 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_view.frustum[i];
2527 // generate a deformed frustum that includes the light origin, this is
2528 // used to cull shadow casting surfaces that can not possibly cast a
2529 // shadow onto the visible light-receiving surfaces, which can be a
2532 // if the light origin is onscreen the result will be 4 planes exactly
2533 // if the light origin is offscreen on only one axis the result will
2534 // be exactly 5 planes (split-side case)
2535 // if the light origin is offscreen on two axes the result will be
2536 // exactly 4 planes (stretched corner case)
2537 for (i = 0;i < 4;i++)
2539 // quickly reject standard frustum planes that put the light
2540 // origin outside the frustum
2541 if (PlaneDiff(rtlight->shadoworigin, &r_view.frustum[i]) < -0.03125)
2544 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_view.frustum[i];
2546 // if all the standard frustum planes were accepted, the light is onscreen
2547 // otherwise we need to generate some more planes below...
2548 if (rsurface.rtlight_numfrustumplanes < 4)
2550 // at least one of the stock frustum planes failed, so we need to
2551 // create one or two custom planes to enclose the light origin
2552 for (i = 0;i < 4;i++)
2554 // create a plane using the view origin and light origin, and a
2555 // single point from the frustum corner set
2556 TriangleNormal(r_view.origin, r_view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2557 VectorNormalize(plane.normal);
2558 plane.dist = DotProduct(r_view.origin, plane.normal);
2559 // see if this plane is backwards and flip it if so
2560 for (j = 0;j < 4;j++)
2561 if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2565 VectorNegate(plane.normal, plane.normal);
2567 // flipped plane, test again to see if it is now valid
2568 for (j = 0;j < 4;j++)
2569 if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2571 // if the plane is still not valid, then it is dividing the
2572 // frustum and has to be rejected
2576 // we have created a valid plane, compute extra info
2577 PlaneClassify(&plane);
2579 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2581 // if we've found 5 frustum planes then we have constructed a
2582 // proper split-side case and do not need to keep searching for
2583 // planes to enclose the light origin
2584 if (rsurface.rtlight_numfrustumplanes == 5)
2592 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
2594 plane = rsurface.rtlight_frustumplanes[i];
2595 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));
2600 // now add the light-space box planes if the light box is rotated, as any
2601 // caster outside the oriented light box is irrelevant (even if it passed
2602 // the worldspace light box, which is axial)
2603 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
2605 for (i = 0;i < 6;i++)
2609 v[i >> 1] = (i & 1) ? -1 : 1;
2610 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
2611 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
2612 plane.dist = VectorNormalizeLength(plane.normal);
2613 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
2614 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2620 // add the world-space reduced box planes
2621 for (i = 0;i < 6;i++)
2623 VectorClear(plane.normal);
2624 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
2625 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
2626 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2635 // reduce all plane distances to tightly fit the rtlight cull box, which
2637 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2638 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2639 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2640 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2641 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2642 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2643 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2644 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2645 oldnum = rsurface.rtlight_numfrustumplanes;
2646 rsurface.rtlight_numfrustumplanes = 0;
2647 for (j = 0;j < oldnum;j++)
2649 // find the nearest point on the box to this plane
2650 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
2651 for (i = 1;i < 8;i++)
2653 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
2654 if (bestdist > dist)
2657 Con_Printf("light %p %splane #%i %f %f %f : %f < %f\n", rtlight, rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125 ? "^2" : "^1", j, rsurface.rtlight_frustumplanes[j].normal[0], rsurface.rtlight_frustumplanes[j].normal[1], rsurface.rtlight_frustumplanes[j].normal[2], rsurface.rtlight_frustumplanes[j].dist, bestdist);
2658 // if the nearest point is near or behind the plane, we want this
2659 // plane, otherwise the plane is useless as it won't cull anything
2660 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
2662 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
2663 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
2670 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2672 RSurf_ActiveWorldEntity();
2673 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2677 for (mesh = rsurface.rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2679 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2680 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
2681 GL_LockArrays(0, mesh->numverts);
2682 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2684 // decrement stencil if backface is behind depthbuffer
2685 GL_CullFace(r_view.cullface_front);
2686 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2687 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2688 // increment stencil if frontface is behind depthbuffer
2689 GL_CullFace(r_view.cullface_back);
2690 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2692 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2693 GL_LockArrays(0, 0);
2697 else if (numsurfaces && r_refdef.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
2700 int surfacelistindex;
2701 msurface_t *surface;
2702 R_Shadow_PrepareShadowMark(r_refdef.worldmodel->brush.shadowmesh->numtriangles);
2703 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2705 surface = r_refdef.worldmodel->data_surfaces + surfacelist[surfacelistindex];
2706 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
2707 if (CHECKPVSBIT(trispvs, t))
2708 shadowmarklist[numshadowmark++] = t;
2710 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, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius + r_refdef.worldmodel->radius*2 + r_shadow_projectdistance.value, numshadowmark, shadowmarklist);
2712 else if (numsurfaces)
2713 r_refdef.worldmodel->DrawShadowVolume(r_refdef.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
2716 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
2718 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2719 vec_t relativeshadowradius;
2720 RSurf_ActiveModelEntity(ent, false, false);
2721 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
2722 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
2723 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2724 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2725 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2726 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2727 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2728 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2729 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2732 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2734 // set up properties for rendering light onto this entity
2735 RSurf_ActiveModelEntity(ent, true, true);
2736 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
2737 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2738 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2739 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2740 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2741 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2744 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2746 if (!r_refdef.worldmodel->DrawLight)
2749 // set up properties for rendering light onto this entity
2750 RSurf_ActiveWorldEntity();
2751 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
2752 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2753 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2754 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2755 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2756 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2758 r_refdef.worldmodel->DrawLight(r_refdef.worldentity, numsurfaces, surfacelist, trispvs);
2761 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2763 model_t *model = ent->model;
2764 if (!model->DrawLight)
2767 R_Shadow_SetupEntityLight(ent);
2769 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist, NULL);
2772 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2776 int numleafs, numsurfaces;
2777 int *leaflist, *surfacelist;
2778 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
2779 int numlightentities;
2780 int numlightentities_noselfshadow;
2781 int numshadowentities;
2782 int numshadowentities_noselfshadow;
2783 entity_render_t *lightentities[MAX_EDICTS];
2784 entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
2785 entity_render_t *shadowentities[MAX_EDICTS];
2786 entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
2788 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2789 // skip lights that are basically invisible (color 0 0 0)
2790 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2793 // loading is done before visibility checks because loading should happen
2794 // all at once at the start of a level, not when it stalls gameplay.
2795 // (especially important to benchmarks)
2797 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2798 R_RTLight_Compile(rtlight);
2800 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2802 // look up the light style value at this time
2803 f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2804 VectorScale(rtlight->color, f, rtlight->currentcolor);
2806 if (rtlight->selected)
2808 f = 2 + sin(realtime * M_PI * 4.0);
2809 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2813 // if lightstyle is currently off, don't draw the light
2814 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2817 // if the light box is offscreen, skip it
2818 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2821 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
2822 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
2824 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2826 // compiled light, world available and can receive realtime lighting
2827 // retrieve leaf information
2828 numleafs = rtlight->static_numleafs;
2829 leaflist = rtlight->static_leaflist;
2830 leafpvs = rtlight->static_leafpvs;
2831 numsurfaces = rtlight->static_numsurfaces;
2832 surfacelist = rtlight->static_surfacelist;
2833 shadowtrispvs = rtlight->static_shadowtrispvs;
2834 lighttrispvs = rtlight->static_lighttrispvs;
2836 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2838 // dynamic light, world available and can receive realtime lighting
2839 // calculate lit surfaces and leafs
2840 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);
2841 r_refdef.worldmodel->GetLightInfo(r_refdef.worldentity, rtlight->shadoworigin, rtlight->radius, rsurface.rtlight_cullmins, rsurface.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);
2842 leaflist = r_shadow_buffer_leaflist;
2843 leafpvs = r_shadow_buffer_leafpvs;
2844 surfacelist = r_shadow_buffer_surfacelist;
2845 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
2846 lighttrispvs = r_shadow_buffer_lighttrispvs;
2847 // if the reduced leaf bounds are offscreen, skip it
2848 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2859 shadowtrispvs = NULL;
2860 lighttrispvs = NULL;
2862 // check if light is illuminating any visible leafs
2865 for (i = 0;i < numleafs;i++)
2866 if (r_viewcache.world_leafvisible[leaflist[i]])
2871 // set up a scissor rectangle for this light
2872 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2875 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
2877 // make a list of lit entities and shadow casting entities
2878 numlightentities = 0;
2879 numlightentities_noselfshadow = 0;
2880 numshadowentities = 0;
2881 numshadowentities_noselfshadow = 0;
2882 // add dynamic entities that are lit by the light
2883 if (r_drawentities.integer)
2885 for (i = 0;i < r_refdef.numentities;i++)
2888 entity_render_t *ent = r_refdef.entities[i];
2890 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2892 // skip the object entirely if it is not within the valid
2893 // shadow-casting region (which includes the lit region)
2894 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
2896 if (!(model = ent->model))
2898 if (r_viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
2900 // this entity wants to receive light, is visible, and is
2901 // inside the light box
2902 // TODO: check if the surfaces in the model can receive light
2903 // so now check if it's in a leaf seen by the light
2904 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2906 if (ent->flags & RENDER_NOSELFSHADOW)
2907 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
2909 lightentities[numlightentities++] = ent;
2910 // since it is lit, it probably also casts a shadow...
2911 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2912 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2913 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2915 // note: exterior models without the RENDER_NOSELFSHADOW
2916 // flag still create a RENDER_NOSELFSHADOW shadow but
2917 // are lit normally, this means that they are
2918 // self-shadowing but do not shadow other
2919 // RENDER_NOSELFSHADOW entities such as the gun
2920 // (very weird, but keeps the player shadow off the gun)
2921 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
2922 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
2924 shadowentities[numshadowentities++] = ent;
2927 else if (ent->flags & RENDER_SHADOW)
2929 // this entity is not receiving light, but may still need to
2931 // TODO: check if the surfaces in the model can cast shadow
2932 // now check if it is in a leaf seen by the light
2933 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2935 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2936 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2937 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2939 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
2940 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
2942 shadowentities[numshadowentities++] = ent;
2948 // return if there's nothing at all to light
2949 if (!numlightentities && !numsurfaces)
2952 // don't let sound skip if going slow
2953 if (r_refdef.extraupdate)
2956 // make this the active rtlight for rendering purposes
2957 R_Shadow_RenderMode_ActiveLight(rtlight);
2958 // count this light in the r_speeds
2959 r_refdef.stats.lights++;
2961 if (r_showshadowvolumes.integer && r_view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2963 // optionally draw visible shape of the shadow volumes
2964 // for performance analysis by level designers
2965 R_Shadow_RenderMode_VisibleShadowVolumes();
2967 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
2968 for (i = 0;i < numshadowentities;i++)
2969 R_Shadow_DrawEntityShadow(shadowentities[i]);
2970 for (i = 0;i < numshadowentities_noselfshadow;i++)
2971 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
2974 if (gl_stencil && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2976 // draw stencil shadow volumes to mask off pixels that are in shadow
2977 // so that they won't receive lighting
2978 R_Shadow_RenderMode_StencilShadowVolumes(true);
2980 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
2981 for (i = 0;i < numshadowentities;i++)
2982 R_Shadow_DrawEntityShadow(shadowentities[i]);
2983 if (numlightentities_noselfshadow)
2985 // draw lighting in the unmasked areas
2986 R_Shadow_RenderMode_Lighting(true, false);
2987 for (i = 0;i < numlightentities_noselfshadow;i++)
2988 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
2990 // optionally draw the illuminated areas
2991 // for performance analysis by level designers
2992 if (r_showlighting.integer && r_view.showdebug)
2994 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
2995 for (i = 0;i < numlightentities_noselfshadow;i++)
2996 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
2999 R_Shadow_RenderMode_StencilShadowVolumes(false);
3001 for (i = 0;i < numshadowentities_noselfshadow;i++)
3002 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3004 if (numsurfaces + numlightentities)
3006 // draw lighting in the unmasked areas
3007 R_Shadow_RenderMode_Lighting(true, false);
3009 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3010 for (i = 0;i < numlightentities;i++)
3011 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3013 // optionally draw the illuminated areas
3014 // for performance analysis by level designers
3015 if (r_showlighting.integer && r_view.showdebug)
3017 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3019 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3020 for (i = 0;i < numlightentities;i++)
3021 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3027 if (numsurfaces + numlightentities)
3029 // draw lighting in the unmasked areas
3030 R_Shadow_RenderMode_Lighting(false, false);
3032 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3033 for (i = 0;i < numlightentities;i++)
3034 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3035 for (i = 0;i < numlightentities_noselfshadow;i++)
3036 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
3038 // optionally draw the illuminated areas
3039 // for performance analysis by level designers
3040 if (r_showlighting.integer && r_view.showdebug)
3042 R_Shadow_RenderMode_VisibleLighting(false, false);
3044 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3045 for (i = 0;i < numlightentities;i++)
3046 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3047 for (i = 0;i < numlightentities_noselfshadow;i++)
3048 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
3054 void R_Shadow_DrawLightSprites(void);
3055 void R_ShadowVolumeLighting(qboolean visible)
3060 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
3061 R_Shadow_EditLights_Reload_f();
3063 if (r_editlights.integer)
3064 R_Shadow_DrawLightSprites();
3066 R_Shadow_RenderMode_Begin();
3068 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3069 if (r_shadow_debuglight.integer >= 0)
3071 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3072 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
3073 R_DrawRTLight(&light->rtlight, visible);
3076 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3077 if (light->flags & flag)
3078 R_DrawRTLight(&light->rtlight, visible);
3079 if (r_refdef.rtdlight)
3080 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
3081 R_DrawRTLight(&r_refdef.lights[lnum], visible);
3083 R_Shadow_RenderMode_End();
3086 extern void R_SetupView(void);
3087 extern cvar_t r_shadows_throwdistance;
3088 void R_DrawModelShadows(void)
3091 float relativethrowdistance;
3092 entity_render_t *ent;
3093 vec3_t relativelightorigin;
3094 vec3_t relativelightdirection;
3095 vec3_t relativeshadowmins, relativeshadowmaxs;
3098 if (!r_drawentities.integer || !gl_stencil)
3102 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
3104 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3106 if (gl_ext_separatestencil.integer)
3107 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
3108 else if (gl_ext_stenciltwoside.integer)
3109 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
3111 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
3113 R_Shadow_RenderMode_StencilShadowVolumes(true);
3115 for (i = 0;i < r_refdef.numentities;i++)
3117 ent = r_refdef.entities[i];
3118 // cast shadows from anything that is not a submodel of the map
3119 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
3121 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3122 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3123 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3124 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3125 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3126 RSurf_ActiveModelEntity(ent, false, false);
3127 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
3131 // not really the right mode, but this will disable any silly stencil features
3132 R_Shadow_RenderMode_VisibleLighting(true, true);
3134 // vertex coordinates for a quad that covers the screen exactly
3135 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
3136 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
3137 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
3138 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
3140 // set up ortho view for rendering this pass
3141 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
3142 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
3143 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
3144 GL_ScissorTest(true);
3145 R_Mesh_Matrix(&identitymatrix);
3146 R_Mesh_ResetTextureState();
3147 R_Mesh_VertexPointer(vertex3f, 0, 0);
3148 R_Mesh_ColorPointer(NULL, 0, 0);
3150 // set up a 50% darkening blend on shadowed areas
3151 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3152 GL_DepthRange(0, 1);
3153 GL_DepthTest(false);
3154 GL_DepthMask(false);
3155 GL_PolygonOffset(0, 0);CHECKGLERROR
3156 GL_Color(0, 0, 0, 0.5);
3157 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
3158 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
3159 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
3160 qglStencilMask(~0);CHECKGLERROR
3161 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3162 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
3164 // apply the blend to the shadowed areas
3165 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3167 // restoring the perspective view is done by R_RenderScene
3170 // restore other state to normal
3171 R_Shadow_RenderMode_End();
3175 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3176 typedef struct suffixinfo_s
3179 qboolean flipx, flipy, flipdiagonal;
3182 static suffixinfo_t suffix[3][6] =
3185 {"px", false, false, false},
3186 {"nx", false, false, false},
3187 {"py", false, false, false},
3188 {"ny", false, false, false},
3189 {"pz", false, false, false},
3190 {"nz", false, false, false}
3193 {"posx", false, false, false},
3194 {"negx", false, false, false},
3195 {"posy", false, false, false},
3196 {"negy", false, false, false},
3197 {"posz", false, false, false},
3198 {"negz", false, false, false}
3201 {"rt", true, false, true},
3202 {"lf", false, true, true},
3203 {"ft", true, true, false},
3204 {"bk", false, false, false},
3205 {"up", true, false, true},
3206 {"dn", true, false, true}
3210 static int componentorder[4] = {0, 1, 2, 3};
3212 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3214 int i, j, cubemapsize;
3215 unsigned char *cubemappixels, *image_buffer;
3216 rtexture_t *cubemaptexture;
3218 // must start 0 so the first loadimagepixels has no requested width/height
3220 cubemappixels = NULL;
3221 cubemaptexture = NULL;
3222 // keep trying different suffix groups (posx, px, rt) until one loads
3223 for (j = 0;j < 3 && !cubemappixels;j++)
3225 // load the 6 images in the suffix group
3226 for (i = 0;i < 6;i++)
3228 // generate an image name based on the base and and suffix
3229 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3231 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
3233 // an image loaded, make sure width and height are equal
3234 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
3236 // if this is the first image to load successfully, allocate the cubemap memory
3237 if (!cubemappixels && image_width >= 1)
3239 cubemapsize = image_width;
3240 // note this clears to black, so unavailable sides are black
3241 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3243 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3245 Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_buffer, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder);
3248 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3250 Mem_Free(image_buffer);
3254 // if a cubemap loaded, upload it
3257 if (!r_shadow_filters_texturepool)
3258 r_shadow_filters_texturepool = R_AllocTexturePool();
3259 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0), NULL);
3260 Mem_Free(cubemappixels);
3264 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3265 for (j = 0;j < 3;j++)
3266 for (i = 0;i < 6;i++)
3267 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3268 Con_Print(" and was unable to find any of them.\n");
3270 return cubemaptexture;
3273 rtexture_t *R_Shadow_Cubemap(const char *basename)
3276 for (i = 0;i < numcubemaps;i++)
3277 if (!strcasecmp(cubemaps[i].basename, basename))
3278 return cubemaps[i].texture;
3279 if (i >= MAX_CUBEMAPS)
3280 return r_texture_whitecube;
3282 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
3283 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3284 if (!cubemaps[i].texture)
3285 cubemaps[i].texture = r_texture_whitecube;
3286 return cubemaps[i].texture;
3289 void R_Shadow_FreeCubemaps(void)
3292 R_FreeTexturePool(&r_shadow_filters_texturepool);
3295 dlight_t *R_Shadow_NewWorldLight(void)
3298 light = (dlight_t *)Mem_Alloc(r_main_mempool, sizeof(dlight_t));
3299 light->next = r_shadow_worldlightchain;
3300 r_shadow_worldlightchain = light;
3304 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)
3307 // validate parameters
3308 if (style < 0 || style >= MAX_LIGHTSTYLES)
3310 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3316 // copy to light properties
3317 VectorCopy(origin, light->origin);
3318 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3319 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3320 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3321 light->color[0] = max(color[0], 0);
3322 light->color[1] = max(color[1], 0);
3323 light->color[2] = max(color[2], 0);
3324 light->radius = max(radius, 0);
3325 light->style = style;
3326 light->shadow = shadowenable;
3327 light->corona = corona;
3328 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3329 light->coronasizescale = coronasizescale;
3330 light->ambientscale = ambientscale;
3331 light->diffusescale = diffusescale;
3332 light->specularscale = specularscale;
3333 light->flags = flags;
3335 // update renderable light data
3336 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
3337 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);
3340 void R_Shadow_FreeWorldLight(dlight_t *light)
3342 dlight_t **lightpointer;
3343 R_RTLight_Uncompile(&light->rtlight);
3344 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3345 if (*lightpointer != light)
3346 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
3347 *lightpointer = light->next;
3351 void R_Shadow_ClearWorldLights(void)
3353 while (r_shadow_worldlightchain)
3354 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3355 r_shadow_selectedlight = NULL;
3356 R_Shadow_FreeCubemaps();
3359 void R_Shadow_SelectLight(dlight_t *light)
3361 if (r_shadow_selectedlight)
3362 r_shadow_selectedlight->selected = false;
3363 r_shadow_selectedlight = light;
3364 if (r_shadow_selectedlight)
3365 r_shadow_selectedlight->selected = true;
3368 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3370 // this is never batched (there can be only one)
3371 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_editlights_sprcursor->tex, NULL, false, false, r_editlights_cursorlocation, r_view.right, r_view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE, 1, 1, 1, 0.5f);
3374 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3380 // this is never batched (due to the ent parameter changing every time)
3381 // so numsurfaces == 1 and surfacelist[0] == lightnumber
3382 const dlight_t *light = (dlight_t *)ent;
3385 if (light->selected)
3386 scaling = 1.25 + 0.25*sin(realtime * M_PI * 1.5);
3387 // vortex: get sprites color (solve 0 0 0 colored light being invisible here)
3388 spritecolor[0] = max(0.1, light->color[0]);
3389 spritecolor[1] = max(0.1, light->color[1]);
3390 spritecolor[2] = max(0.1, light->color[2]);
3392 // draw light sprite
3396 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_editlights_sprnoshadowlight->tex, NULL, false, false, light->origin, r_view.right, r_view.up, EDLIGHTSPRSIZE*scaling, -EDLIGHTSPRSIZE*scaling, -EDLIGHTSPRSIZE*scaling, EDLIGHTSPRSIZE*scaling, spritecolor[0]*intensity, spritecolor[1]*intensity, spritecolor[2]*intensity, 1);
3399 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_editlights_sprlight->tex, NULL, false, false, light->origin, r_view.right, r_view.up, EDLIGHTSELECTSPRSIZE*scaling, -EDLIGHTSELECTSPRSIZE*scaling, -EDLIGHTSELECTSPRSIZE*scaling, EDLIGHTSELECTSPRSIZE*scaling, spritecolor[0]*intensity, spritecolor[1]*intensity, spritecolor[2]*intensity, 1);
3400 // draw cubemap sprite over light
3401 if (light->cubemapname[0])
3402 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_editlights_sprcubemap->tex, NULL, false, false, light->origin, r_view.right, r_view.up, EDLIGHTSPRSIZE*scaling, -EDLIGHTSPRSIZE*scaling, -EDLIGHTSPRSIZE*scaling, EDLIGHTSPRSIZE*scaling, spritecolor[0]*intensity, spritecolor[1]*intensity, spritecolor[2]*intensity, 1);
3403 // draw selection sprite if light is selected
3404 if (light->selected)
3405 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_editlights_sprselection->tex, NULL, false, false, light->origin, r_view.right, r_view.up, EDLIGHTSPRSIZE*scaling, -EDLIGHTSPRSIZE*scaling, -EDLIGHTSPRSIZE*scaling, EDLIGHTSPRSIZE*scaling, spritecolor[0]*intensity, spritecolor[1]*intensity, spritecolor[2]*intensity, 1);
3406 // VorteX todo: add normalmode/realtime mode light overlay sprites?
3409 void R_Shadow_DrawLightSprites(void)
3414 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3415 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 1+(i % 5), &light->rtlight);
3416 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
3419 void R_Shadow_SelectLightInView(void)
3421 float bestrating, rating, temp[3];
3422 dlight_t *best, *light;
3425 for (light = r_shadow_worldlightchain;light;light = light->next)
3427 VectorSubtract(light->origin, r_view.origin, temp);
3428 rating = (DotProduct(temp, r_view.forward) / sqrt(DotProduct(temp, temp)));
3431 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3432 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)
3434 bestrating = rating;
3439 R_Shadow_SelectLight(best);
3442 void R_Shadow_LoadWorldLights(void)
3444 int n, a, style, shadow, flags;
3445 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3446 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3447 if (r_refdef.worldmodel == NULL)
3449 Con_Print("No map loaded.\n");
3452 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3453 strlcat (name, ".rtlights", sizeof (name));
3454 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3464 for (;COM_Parse(t, true) && strcmp(
3465 if (COM_Parse(t, true))
3467 if (com_token[0] == '!')
3470 origin[0] = atof(com_token+1);
3473 origin[0] = atof(com_token);
3478 while (*s && *s != '\n' && *s != '\r')
3484 // check for modifier flags
3491 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);
3494 flags = LIGHTFLAG_REALTIMEMODE;
3502 coronasizescale = 0.25f;
3504 VectorClear(angles);
3507 if (a < 9 || !strcmp(cubemapname, "\"\""))
3509 // remove quotes on cubemapname
3510 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3513 namelen = strlen(cubemapname) - 2;
3514 memmove(cubemapname, cubemapname + 1, namelen);
3515 cubemapname[namelen] = '\0';
3519 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);
3522 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3530 Con_Printf("invalid rtlights file \"%s\"\n", name);
3531 Mem_Free(lightsstring);
3535 void R_Shadow_SaveWorldLights(void)
3538 size_t bufchars, bufmaxchars;
3540 char name[MAX_QPATH];
3541 char line[MAX_INPUTLINE];
3542 if (!r_shadow_worldlightchain)
3544 if (r_refdef.worldmodel == NULL)
3546 Con_Print("No map loaded.\n");
3549 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3550 strlcat (name, ".rtlights", sizeof (name));
3551 bufchars = bufmaxchars = 0;
3553 for (light = r_shadow_worldlightchain;light;light = light->next)
3555 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3556 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);
3557 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3558 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]);
3560 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);
3561 if (bufchars + strlen(line) > bufmaxchars)
3563 bufmaxchars = bufchars + strlen(line) + 2048;
3565 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3569 memcpy(buf, oldbuf, bufchars);
3575 memcpy(buf + bufchars, line, strlen(line));
3576 bufchars += strlen(line);
3580 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3585 void R_Shadow_LoadLightsFile(void)
3588 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3589 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3590 if (r_refdef.worldmodel == NULL)
3592 Con_Print("No map loaded.\n");
3595 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3596 strlcat (name, ".lights", sizeof (name));
3597 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3605 while (*s && *s != '\n' && *s != '\r')
3611 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);
3615 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);
3618 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3619 radius = bound(15, radius, 4096);
3620 VectorScale(color, (2.0f / (8388608.0f)), color);
3621 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3629 Con_Printf("invalid lights file \"%s\"\n", name);
3630 Mem_Free(lightsstring);
3634 // tyrlite/hmap2 light types in the delay field
3635 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3637 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3639 int entnum, style, islight, skin, pflags, effects, type, n;
3642 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3643 char key[256], value[MAX_INPUTLINE];
3645 if (r_refdef.worldmodel == NULL)
3647 Con_Print("No map loaded.\n");
3650 // try to load a .ent file first
3651 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3652 strlcat (key, ".ent", sizeof (key));
3653 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3654 // and if that is not found, fall back to the bsp file entity string
3656 data = r_refdef.worldmodel->brush.entities;
3659 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
3661 type = LIGHTTYPE_MINUSX;
3662 origin[0] = origin[1] = origin[2] = 0;
3663 originhack[0] = originhack[1] = originhack[2] = 0;
3664 angles[0] = angles[1] = angles[2] = 0;
3665 color[0] = color[1] = color[2] = 1;
3666 light[0] = light[1] = light[2] = 1;light[3] = 300;
3667 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3677 if (!COM_ParseToken_Simple(&data, false, false))
3679 if (com_token[0] == '}')
3680 break; // end of entity
3681 if (com_token[0] == '_')
3682 strlcpy(key, com_token + 1, sizeof(key));
3684 strlcpy(key, com_token, sizeof(key));
3685 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3686 key[strlen(key)-1] = 0;
3687 if (!COM_ParseToken_Simple(&data, false, false))
3689 strlcpy(value, com_token, sizeof(value));
3691 // now that we have the key pair worked out...
3692 if (!strcmp("light", key))
3694 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3698 light[0] = vec[0] * (1.0f / 256.0f);
3699 light[1] = vec[0] * (1.0f / 256.0f);
3700 light[2] = vec[0] * (1.0f / 256.0f);
3706 light[0] = vec[0] * (1.0f / 255.0f);
3707 light[1] = vec[1] * (1.0f / 255.0f);
3708 light[2] = vec[2] * (1.0f / 255.0f);
3712 else if (!strcmp("delay", key))
3714 else if (!strcmp("origin", key))
3715 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3716 else if (!strcmp("angle", key))
3717 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3718 else if (!strcmp("angles", key))
3719 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3720 else if (!strcmp("color", key))
3721 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3722 else if (!strcmp("wait", key))
3723 fadescale = atof(value);
3724 else if (!strcmp("classname", key))
3726 if (!strncmp(value, "light", 5))
3729 if (!strcmp(value, "light_fluoro"))
3734 overridecolor[0] = 1;
3735 overridecolor[1] = 1;
3736 overridecolor[2] = 1;
3738 if (!strcmp(value, "light_fluorospark"))
3743 overridecolor[0] = 1;
3744 overridecolor[1] = 1;
3745 overridecolor[2] = 1;
3747 if (!strcmp(value, "light_globe"))
3752 overridecolor[0] = 1;
3753 overridecolor[1] = 0.8;
3754 overridecolor[2] = 0.4;
3756 if (!strcmp(value, "light_flame_large_yellow"))
3761 overridecolor[0] = 1;
3762 overridecolor[1] = 0.5;
3763 overridecolor[2] = 0.1;
3765 if (!strcmp(value, "light_flame_small_yellow"))
3770 overridecolor[0] = 1;
3771 overridecolor[1] = 0.5;
3772 overridecolor[2] = 0.1;
3774 if (!strcmp(value, "light_torch_small_white"))
3779 overridecolor[0] = 1;
3780 overridecolor[1] = 0.5;
3781 overridecolor[2] = 0.1;
3783 if (!strcmp(value, "light_torch_small_walltorch"))
3788 overridecolor[0] = 1;
3789 overridecolor[1] = 0.5;
3790 overridecolor[2] = 0.1;
3794 else if (!strcmp("style", key))
3795 style = atoi(value);
3796 else if (!strcmp("skin", key))
3797 skin = (int)atof(value);
3798 else if (!strcmp("pflags", key))
3799 pflags = (int)atof(value);
3800 else if (!strcmp("effects", key))
3801 effects = (int)atof(value);
3802 else if (r_refdef.worldmodel->type == mod_brushq3)
3804 if (!strcmp("scale", key))
3805 lightscale = atof(value);
3806 if (!strcmp("fade", key))
3807 fadescale = atof(value);
3812 if (lightscale <= 0)
3816 if (color[0] == color[1] && color[0] == color[2])
3818 color[0] *= overridecolor[0];
3819 color[1] *= overridecolor[1];
3820 color[2] *= overridecolor[2];
3822 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3823 color[0] = color[0] * light[0];
3824 color[1] = color[1] * light[1];
3825 color[2] = color[2] * light[2];
3828 case LIGHTTYPE_MINUSX:
3830 case LIGHTTYPE_RECIPX:
3832 VectorScale(color, (1.0f / 16.0f), color);
3834 case LIGHTTYPE_RECIPXX:
3836 VectorScale(color, (1.0f / 16.0f), color);
3839 case LIGHTTYPE_NONE:
3843 case LIGHTTYPE_MINUSXX:
3846 VectorAdd(origin, originhack, origin);
3848 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);
3851 Mem_Free(entfiledata);
3855 void R_Shadow_SetCursorLocationForView(void)
3858 vec3_t dest, endpos;
3860 VectorMA(r_view.origin, r_editlights_cursordistance.value, r_view.forward, dest);
3861 trace = CL_Move(r_view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
3862 if (trace.fraction < 1)
3864 dist = trace.fraction * r_editlights_cursordistance.value;
3865 push = r_editlights_cursorpushback.value;
3869 VectorMA(trace.endpos, push, r_view.forward, endpos);
3870 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3874 VectorClear( endpos );
3876 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3877 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3878 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3881 void R_Shadow_UpdateWorldLightSelection(void)
3883 if (r_editlights.integer)
3885 R_Shadow_SetCursorLocationForView();
3886 R_Shadow_SelectLightInView();
3889 R_Shadow_SelectLight(NULL);
3892 void R_Shadow_EditLights_Clear_f(void)
3894 R_Shadow_ClearWorldLights();
3897 void R_Shadow_EditLights_Reload_f(void)
3899 if (!r_refdef.worldmodel)
3901 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3902 R_Shadow_ClearWorldLights();
3903 R_Shadow_LoadWorldLights();
3904 if (r_shadow_worldlightchain == NULL)
3906 R_Shadow_LoadLightsFile();
3907 if (r_shadow_worldlightchain == NULL)
3908 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3912 void R_Shadow_EditLights_Save_f(void)
3914 if (!r_refdef.worldmodel)
3916 R_Shadow_SaveWorldLights();
3919 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3921 R_Shadow_ClearWorldLights();
3922 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3925 void R_Shadow_EditLights_ImportLightsFile_f(void)
3927 R_Shadow_ClearWorldLights();
3928 R_Shadow_LoadLightsFile();
3931 void R_Shadow_EditLights_Spawn_f(void)
3934 if (!r_editlights.integer)
3936 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3939 if (Cmd_Argc() != 1)
3941 Con_Print("r_editlights_spawn does not take parameters\n");
3944 color[0] = color[1] = color[2] = 1;
3945 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3948 void R_Shadow_EditLights_Edit_f(void)
3950 vec3_t origin, angles, color;
3951 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3952 int style, shadows, flags, normalmode, realtimemode;
3953 char cubemapname[MAX_INPUTLINE];
3954 if (!r_editlights.integer)
3956 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3959 if (!r_shadow_selectedlight)
3961 Con_Print("No selected light.\n");
3964 VectorCopy(r_shadow_selectedlight->origin, origin);
3965 VectorCopy(r_shadow_selectedlight->angles, angles);
3966 VectorCopy(r_shadow_selectedlight->color, color);
3967 radius = r_shadow_selectedlight->radius;
3968 style = r_shadow_selectedlight->style;
3969 if (r_shadow_selectedlight->cubemapname)
3970 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3973 shadows = r_shadow_selectedlight->shadow;
3974 corona = r_shadow_selectedlight->corona;
3975 coronasizescale = r_shadow_selectedlight->coronasizescale;
3976 ambientscale = r_shadow_selectedlight->ambientscale;
3977 diffusescale = r_shadow_selectedlight->diffusescale;
3978 specularscale = r_shadow_selectedlight->specularscale;
3979 flags = r_shadow_selectedlight->flags;
3980 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3981 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3982 if (!strcmp(Cmd_Argv(1), "origin"))
3984 if (Cmd_Argc() != 5)
3986 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3989 origin[0] = atof(Cmd_Argv(2));
3990 origin[1] = atof(Cmd_Argv(3));
3991 origin[2] = atof(Cmd_Argv(4));
3993 else if (!strcmp(Cmd_Argv(1), "originx"))
3995 if (Cmd_Argc() != 3)
3997 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4000 origin[0] = atof(Cmd_Argv(2));
4002 else if (!strcmp(Cmd_Argv(1), "originy"))
4004 if (Cmd_Argc() != 3)
4006 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4009 origin[1] = atof(Cmd_Argv(2));
4011 else if (!strcmp(Cmd_Argv(1), "originz"))
4013 if (Cmd_Argc() != 3)
4015 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4018 origin[2] = atof(Cmd_Argv(2));
4020 else if (!strcmp(Cmd_Argv(1), "move"))
4022 if (Cmd_Argc() != 5)
4024 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4027 origin[0] += atof(Cmd_Argv(2));
4028 origin[1] += atof(Cmd_Argv(3));
4029 origin[2] += atof(Cmd_Argv(4));
4031 else if (!strcmp(Cmd_Argv(1), "movex"))
4033 if (Cmd_Argc() != 3)
4035 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4038 origin[0] += atof(Cmd_Argv(2));
4040 else if (!strcmp(Cmd_Argv(1), "movey"))
4042 if (Cmd_Argc() != 3)
4044 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4047 origin[1] += atof(Cmd_Argv(2));
4049 else if (!strcmp(Cmd_Argv(1), "movez"))
4051 if (Cmd_Argc() != 3)
4053 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4056 origin[2] += atof(Cmd_Argv(2));
4058 else if (!strcmp(Cmd_Argv(1), "angles"))
4060 if (Cmd_Argc() != 5)
4062 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4065 angles[0] = atof(Cmd_Argv(2));
4066 angles[1] = atof(Cmd_Argv(3));
4067 angles[2] = atof(Cmd_Argv(4));
4069 else if (!strcmp(Cmd_Argv(1), "anglesx"))
4071 if (Cmd_Argc() != 3)
4073 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4076 angles[0] = atof(Cmd_Argv(2));
4078 else if (!strcmp(Cmd_Argv(1), "anglesy"))
4080 if (Cmd_Argc() != 3)
4082 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4085 angles[1] = atof(Cmd_Argv(2));
4087 else if (!strcmp(Cmd_Argv(1), "anglesz"))
4089 if (Cmd_Argc() != 3)
4091 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4094 angles[2] = atof(Cmd_Argv(2));
4096 else if (!strcmp(Cmd_Argv(1), "color"))
4098 if (Cmd_Argc() != 5)
4100 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
4103 color[0] = atof(Cmd_Argv(2));
4104 color[1] = atof(Cmd_Argv(3));
4105 color[2] = atof(Cmd_Argv(4));
4107 else if (!strcmp(Cmd_Argv(1), "radius"))
4109 if (Cmd_Argc() != 3)
4111 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4114 radius = atof(Cmd_Argv(2));
4116 else if (!strcmp(Cmd_Argv(1), "colorscale"))
4118 if (Cmd_Argc() == 3)
4120 double scale = atof(Cmd_Argv(2));
4127 if (Cmd_Argc() != 5)
4129 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
4132 color[0] *= atof(Cmd_Argv(2));
4133 color[1] *= atof(Cmd_Argv(3));
4134 color[2] *= atof(Cmd_Argv(4));
4137 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
4139 if (Cmd_Argc() != 3)
4141 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4144 radius *= atof(Cmd_Argv(2));
4146 else if (!strcmp(Cmd_Argv(1), "style"))
4148 if (Cmd_Argc() != 3)
4150 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4153 style = atoi(Cmd_Argv(2));
4155 else if (!strcmp(Cmd_Argv(1), "cubemap"))
4159 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4162 if (Cmd_Argc() == 3)
4163 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
4167 else if (!strcmp(Cmd_Argv(1), "shadows"))
4169 if (Cmd_Argc() != 3)
4171 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4174 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4176 else if (!strcmp(Cmd_Argv(1), "corona"))
4178 if (Cmd_Argc() != 3)
4180 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4183 corona = atof(Cmd_Argv(2));
4185 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4187 if (Cmd_Argc() != 3)
4189 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4192 coronasizescale = atof(Cmd_Argv(2));
4194 else if (!strcmp(Cmd_Argv(1), "ambient"))
4196 if (Cmd_Argc() != 3)
4198 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4201 ambientscale = atof(Cmd_Argv(2));
4203 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4205 if (Cmd_Argc() != 3)
4207 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4210 diffusescale = atof(Cmd_Argv(2));
4212 else if (!strcmp(Cmd_Argv(1), "specular"))
4214 if (Cmd_Argc() != 3)
4216 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4219 specularscale = atof(Cmd_Argv(2));
4221 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4223 if (Cmd_Argc() != 3)
4225 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4228 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4230 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4232 if (Cmd_Argc() != 3)
4234 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4237 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4241 Con_Print("usage: r_editlights_edit [property] [value]\n");
4242 Con_Print("Selected light's properties:\n");
4243 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4244 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4245 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4246 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4247 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4248 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4249 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4250 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4251 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4252 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4253 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4254 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4255 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4256 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4259 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4260 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4263 void R_Shadow_EditLights_EditAll_f(void)
4267 if (!r_editlights.integer)
4269 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4273 for (light = r_shadow_worldlightchain;light;light = light->next)
4275 R_Shadow_SelectLight(light);
4276 R_Shadow_EditLights_Edit_f();
4280 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4282 int lightnumber, lightcount;
4286 if (!r_editlights.integer)
4288 x = vid_conwidth.value - 240;
4290 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
4293 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4294 if (light == r_shadow_selectedlight)
4295 lightnumber = lightcount;
4296 sprintf(temp, "Cursor origin: %.0f %.0f %.0f", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2]); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false);y += 8;
4297 sprintf(temp, "Total lights : %i", lightcount); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false);y += 8;
4299 if (r_shadow_selectedlight == NULL)
4301 sprintf(temp, "Light #%i properties:", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4302 sprintf(temp, "Origin : %.0f %.0f %.0f\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, NULL, true);y += 8;
4303 sprintf(temp, "Angles : %.0f %.0f %.0f\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, NULL, true);y += 8;
4304 sprintf(temp, "Color : %.2f %.2f %.2f\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, NULL, true);y += 8;
4305 sprintf(temp, "Radius : %.0f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4306 sprintf(temp, "Corona : %.0f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4307 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4308 sprintf(temp, "Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4309 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4310 sprintf(temp, "CoronaSize : %.2f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4311 sprintf(temp, "Ambient : %.2f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4312 sprintf(temp, "Diffuse : %.2f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4313 sprintf(temp, "Specular : %.2f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4314 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, NULL, true);y += 8;
4315 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, NULL, true);y += 8;
4318 void R_Shadow_EditLights_ToggleShadow_f(void)
4320 if (!r_editlights.integer)
4322 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4325 if (!r_shadow_selectedlight)
4327 Con_Print("No selected light.\n");
4330 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);
4333 void R_Shadow_EditLights_ToggleCorona_f(void)
4335 if (!r_editlights.integer)
4337 Con_Print("Cannot spawn light 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_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);
4348 void R_Shadow_EditLights_Remove_f(void)
4350 if (!r_editlights.integer)
4352 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4355 if (!r_shadow_selectedlight)
4357 Con_Print("No selected light.\n");
4360 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4361 r_shadow_selectedlight = NULL;
4364 void R_Shadow_EditLights_Help_f(void)
4367 "Documentation on r_editlights system:\n"
4369 "r_editlights : enable/disable editing mode\n"
4370 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4371 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4372 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4373 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4374 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4376 "r_editlights_help : this help\n"
4377 "r_editlights_clear : remove all lights\n"
4378 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4379 "r_editlights_save : save to .rtlights file\n"
4380 "r_editlights_spawn : create a light with default settings\n"
4381 "r_editlights_edit command : edit selected light - more documentation below\n"
4382 "r_editlights_remove : remove selected light\n"
4383 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4384 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4385 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4387 "origin x y z : set light location\n"
4388 "originx x: set x component of light location\n"
4389 "originy y: set y component of light location\n"
4390 "originz z: set z component of light location\n"
4391 "move x y z : adjust light location\n"
4392 "movex x: adjust x component of light location\n"
4393 "movey y: adjust y component of light location\n"
4394 "movez z: adjust z component of light location\n"
4395 "angles x y z : set light angles\n"
4396 "anglesx x: set x component of light angles\n"
4397 "anglesy y: set y component of light angles\n"
4398 "anglesz z: set z component of light angles\n"
4399 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4400 "radius radius : set radius (size) of light\n"
4401 "colorscale grey : multiply color of light (1 does nothing)\n"
4402 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4403 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4404 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4405 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4406 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4407 "shadows 1/0 : turn on/off shadows\n"
4408 "corona n : set corona intensity\n"
4409 "coronasize n : set corona size (0-1)\n"
4410 "ambient n : set ambient intensity (0-1)\n"
4411 "diffuse n : set diffuse intensity (0-1)\n"
4412 "specular n : set specular intensity (0-1)\n"
4413 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4414 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4415 "<nothing> : print light properties to console\n"
4419 void R_Shadow_EditLights_CopyInfo_f(void)
4421 if (!r_editlights.integer)
4423 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4426 if (!r_shadow_selectedlight)
4428 Con_Print("No selected light.\n");
4431 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4432 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4433 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4434 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4435 if (r_shadow_selectedlight->cubemapname)
4436 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
4438 r_shadow_bufferlight.cubemapname[0] = 0;
4439 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4440 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4441 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4442 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4443 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4444 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4445 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4448 void R_Shadow_EditLights_PasteInfo_f(void)
4450 if (!r_editlights.integer)
4452 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4455 if (!r_shadow_selectedlight)
4457 Con_Print("No selected light.\n");
4460 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);
4463 void R_Shadow_EditLights_Init(void)
4465 Cvar_RegisterVariable(&r_editlights);
4466 Cvar_RegisterVariable(&r_editlights_cursordistance);
4467 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4468 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4469 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4470 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4471 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
4472 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
4473 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)");
4474 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
4475 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
4476 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
4477 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)");
4478 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
4479 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
4480 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
4481 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
4482 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
4483 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
4484 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)");