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_visitingleafpvs;
182 unsigned char *r_shadow_buffer_leafpvs;
183 int *r_shadow_buffer_leaflist;
185 int r_shadow_buffer_numsurfacepvsbytes;
186 unsigned char *r_shadow_buffer_surfacepvs;
187 int *r_shadow_buffer_surfacelist;
189 int r_shadow_buffer_numshadowtrispvsbytes;
190 unsigned char *r_shadow_buffer_shadowtrispvs;
191 int r_shadow_buffer_numlighttrispvsbytes;
192 unsigned char *r_shadow_buffer_lighttrispvs;
194 rtexturepool_t *r_shadow_texturepool;
195 rtexture_t *r_shadow_attenuationgradienttexture;
196 rtexture_t *r_shadow_attenuation2dtexture;
197 rtexture_t *r_shadow_attenuation3dtexture;
198 rtexture_t *r_shadow_lightcorona;
200 // lights are reloaded when this changes
201 char r_shadow_mapname[MAX_QPATH];
203 // used only for light filters (cubemaps)
204 rtexturepool_t *r_shadow_filters_texturepool;
206 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"};
207 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"};
208 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
209 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
210 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)"};
211 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"};
212 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
213 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
214 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
215 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
216 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
217 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
218 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
219 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
220 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)"};
221 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
222 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
223 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
224 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
225 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)"};
226 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"};
227 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
228 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
229 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"};
230 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
231 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
232 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)"};
233 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
234 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
235 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)"};
236 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)"};
237 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
238 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
239 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
240 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
241 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
242 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
243 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
244 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
245 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
246 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
248 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
249 #define ATTENTABLESIZE 256
250 // 1D gradient, 2D circle and 3D sphere attenuation textures
251 #define ATTEN1DSIZE 32
252 #define ATTEN2DSIZE 64
253 #define ATTEN3DSIZE 32
255 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
256 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
257 static float r_shadow_attentable[ATTENTABLESIZE+1];
259 rtlight_t *r_shadow_compilingrtlight;
260 static memexpandablearray_t r_shadow_worldlightsarray;
261 dlight_t *r_shadow_selectedlight;
262 dlight_t r_shadow_bufferlight;
263 vec3_t r_editlights_cursorlocation;
265 extern int con_vislines;
267 typedef struct cubemapinfo_s
274 #define MAX_CUBEMAPS 256
275 static int numcubemaps;
276 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
278 void R_Shadow_UncompileWorldLights(void);
279 void R_Shadow_ClearWorldLights(void);
280 void R_Shadow_SaveWorldLights(void);
281 void R_Shadow_LoadWorldLights(void);
282 void R_Shadow_LoadLightsFile(void);
283 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
284 void R_Shadow_EditLights_Reload_f(void);
285 void R_Shadow_ValidateCvars(void);
286 static void R_Shadow_MakeTextures(void);
288 // VorteX: custom editor light sprites
289 #define EDLIGHTSPRSIZE 8
290 cachepic_t *r_editlights_sprcursor;
291 cachepic_t *r_editlights_sprlight;
292 cachepic_t *r_editlights_sprnoshadowlight;
293 cachepic_t *r_editlights_sprcubemaplight;
294 cachepic_t *r_editlights_sprcubemapnoshadowlight;
295 cachepic_t *r_editlights_sprselection;
297 void r_shadow_start(void)
299 // allocate vertex processing arrays
301 r_shadow_attenuationgradienttexture = NULL;
302 r_shadow_attenuation2dtexture = NULL;
303 r_shadow_attenuation3dtexture = NULL;
304 r_shadow_texturepool = NULL;
305 r_shadow_filters_texturepool = NULL;
306 R_Shadow_ValidateCvars();
307 R_Shadow_MakeTextures();
308 maxshadowtriangles = 0;
309 shadowelements = NULL;
310 maxshadowvertices = 0;
311 shadowvertex3f = NULL;
319 shadowmarklist = NULL;
321 r_shadow_buffer_numleafpvsbytes = 0;
322 r_shadow_buffer_visitingleafpvs = NULL;
323 r_shadow_buffer_leafpvs = NULL;
324 r_shadow_buffer_leaflist = NULL;
325 r_shadow_buffer_numsurfacepvsbytes = 0;
326 r_shadow_buffer_surfacepvs = NULL;
327 r_shadow_buffer_surfacelist = NULL;
328 r_shadow_buffer_numshadowtrispvsbytes = 0;
329 r_shadow_buffer_shadowtrispvs = NULL;
330 r_shadow_buffer_numlighttrispvsbytes = 0;
331 r_shadow_buffer_lighttrispvs = NULL;
334 void r_shadow_shutdown(void)
336 R_Shadow_UncompileWorldLights();
338 r_shadow_attenuationgradienttexture = NULL;
339 r_shadow_attenuation2dtexture = NULL;
340 r_shadow_attenuation3dtexture = NULL;
341 R_FreeTexturePool(&r_shadow_texturepool);
342 R_FreeTexturePool(&r_shadow_filters_texturepool);
343 maxshadowtriangles = 0;
345 Mem_Free(shadowelements);
346 shadowelements = NULL;
348 Mem_Free(shadowvertex3f);
349 shadowvertex3f = NULL;
352 Mem_Free(vertexupdate);
355 Mem_Free(vertexremap);
361 Mem_Free(shadowmark);
364 Mem_Free(shadowmarklist);
365 shadowmarklist = NULL;
367 r_shadow_buffer_numleafpvsbytes = 0;
368 if (r_shadow_buffer_visitingleafpvs)
369 Mem_Free(r_shadow_buffer_visitingleafpvs);
370 r_shadow_buffer_visitingleafpvs = NULL;
371 if (r_shadow_buffer_leafpvs)
372 Mem_Free(r_shadow_buffer_leafpvs);
373 r_shadow_buffer_leafpvs = NULL;
374 if (r_shadow_buffer_leaflist)
375 Mem_Free(r_shadow_buffer_leaflist);
376 r_shadow_buffer_leaflist = NULL;
377 r_shadow_buffer_numsurfacepvsbytes = 0;
378 if (r_shadow_buffer_surfacepvs)
379 Mem_Free(r_shadow_buffer_surfacepvs);
380 r_shadow_buffer_surfacepvs = NULL;
381 if (r_shadow_buffer_surfacelist)
382 Mem_Free(r_shadow_buffer_surfacelist);
383 r_shadow_buffer_surfacelist = NULL;
384 r_shadow_buffer_numshadowtrispvsbytes = 0;
385 if (r_shadow_buffer_shadowtrispvs)
386 Mem_Free(r_shadow_buffer_shadowtrispvs);
387 r_shadow_buffer_numlighttrispvsbytes = 0;
388 if (r_shadow_buffer_lighttrispvs)
389 Mem_Free(r_shadow_buffer_lighttrispvs);
392 void r_shadow_newmap(void)
394 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
395 R_Shadow_EditLights_Reload_f();
398 void R_Shadow_Help_f(void)
401 "Documentation on r_shadow system:\n"
403 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
404 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
405 "r_shadow_debuglight : render only this light number (-1 = all)\n"
406 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
407 "r_shadow_gloss2intensity : brightness of forced gloss\n"
408 "r_shadow_glossintensity : brightness of textured gloss\n"
409 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
410 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
411 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
412 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
413 "r_shadow_portallight : use portal visibility for static light precomputation\n"
414 "r_shadow_projectdistance : shadow volume projection distance\n"
415 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
416 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
417 "r_shadow_realtime_world : use high quality world lighting mode\n"
418 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
419 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
420 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
421 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
422 "r_shadow_scissor : use scissor optimization\n"
423 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
424 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
425 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
426 "r_showlighting : useful for performance testing; bright = slow!\n"
427 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
429 "r_shadow_help : this help\n"
433 void R_Shadow_Init(void)
435 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
436 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
437 Cvar_RegisterVariable(&r_shadow_usenormalmap);
438 Cvar_RegisterVariable(&r_shadow_debuglight);
439 Cvar_RegisterVariable(&r_shadow_gloss);
440 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
441 Cvar_RegisterVariable(&r_shadow_glossintensity);
442 Cvar_RegisterVariable(&r_shadow_glossexponent);
443 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
444 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
445 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
446 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
447 Cvar_RegisterVariable(&r_shadow_portallight);
448 Cvar_RegisterVariable(&r_shadow_projectdistance);
449 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
450 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
451 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
452 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
453 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
454 Cvar_RegisterVariable(&r_shadow_realtime_world);
455 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
456 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
457 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
458 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
459 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
460 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
461 Cvar_RegisterVariable(&r_shadow_scissor);
462 Cvar_RegisterVariable(&r_shadow_culltriangles);
463 Cvar_RegisterVariable(&r_shadow_polygonfactor);
464 Cvar_RegisterVariable(&r_shadow_polygonoffset);
465 Cvar_RegisterVariable(&r_shadow_texture3d);
466 Cvar_RegisterVariable(&r_coronas);
467 Cvar_RegisterVariable(&gl_flashblend);
468 Cvar_RegisterVariable(&gl_ext_separatestencil);
469 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
470 if (gamemode == GAME_TENEBRAE)
472 Cvar_SetValue("r_shadow_gloss", 2);
473 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
475 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
476 R_Shadow_EditLights_Init();
477 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
478 maxshadowtriangles = 0;
479 shadowelements = NULL;
480 maxshadowvertices = 0;
481 shadowvertex3f = NULL;
489 shadowmarklist = NULL;
491 r_shadow_buffer_numleafpvsbytes = 0;
492 r_shadow_buffer_visitingleafpvs = NULL;
493 r_shadow_buffer_leafpvs = NULL;
494 r_shadow_buffer_leaflist = NULL;
495 r_shadow_buffer_numsurfacepvsbytes = 0;
496 r_shadow_buffer_surfacepvs = NULL;
497 r_shadow_buffer_surfacelist = NULL;
498 r_shadow_buffer_shadowtrispvs = NULL;
499 r_shadow_buffer_lighttrispvs = NULL;
500 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
503 matrix4x4_t matrix_attenuationxyz =
506 {0.5, 0.0, 0.0, 0.5},
507 {0.0, 0.5, 0.0, 0.5},
508 {0.0, 0.0, 0.5, 0.5},
513 matrix4x4_t matrix_attenuationz =
516 {0.0, 0.0, 0.5, 0.5},
517 {0.0, 0.0, 0.0, 0.5},
518 {0.0, 0.0, 0.0, 0.5},
523 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
525 // make sure shadowelements is big enough for this volume
526 if (maxshadowtriangles < numtriangles)
528 maxshadowtriangles = numtriangles;
530 Mem_Free(shadowelements);
531 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
533 // make sure shadowvertex3f is big enough for this volume
534 if (maxshadowvertices < numvertices)
536 maxshadowvertices = numvertices;
538 Mem_Free(shadowvertex3f);
539 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
543 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
545 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
546 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
547 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
548 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
549 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
551 if (r_shadow_buffer_visitingleafpvs)
552 Mem_Free(r_shadow_buffer_visitingleafpvs);
553 if (r_shadow_buffer_leafpvs)
554 Mem_Free(r_shadow_buffer_leafpvs);
555 if (r_shadow_buffer_leaflist)
556 Mem_Free(r_shadow_buffer_leaflist);
557 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
558 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
559 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
560 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
562 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
564 if (r_shadow_buffer_surfacepvs)
565 Mem_Free(r_shadow_buffer_surfacepvs);
566 if (r_shadow_buffer_surfacelist)
567 Mem_Free(r_shadow_buffer_surfacelist);
568 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
569 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
570 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
572 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
574 if (r_shadow_buffer_shadowtrispvs)
575 Mem_Free(r_shadow_buffer_shadowtrispvs);
576 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
577 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
579 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
581 if (r_shadow_buffer_lighttrispvs)
582 Mem_Free(r_shadow_buffer_lighttrispvs);
583 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
584 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
588 void R_Shadow_PrepareShadowMark(int numtris)
590 // make sure shadowmark is big enough for this volume
591 if (maxshadowmark < numtris)
593 maxshadowmark = numtris;
595 Mem_Free(shadowmark);
597 Mem_Free(shadowmarklist);
598 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
599 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
603 // if shadowmarkcount wrapped we clear the array and adjust accordingly
604 if (shadowmarkcount == 0)
607 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
612 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)
615 int outtriangles = 0, outvertices = 0;
618 float ratio, direction[3], projectvector[3];
620 if (projectdirection)
621 VectorScale(projectdirection, projectdistance, projectvector);
623 VectorClear(projectvector);
625 if (maxvertexupdate < innumvertices)
627 maxvertexupdate = innumvertices;
629 Mem_Free(vertexupdate);
631 Mem_Free(vertexremap);
632 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
633 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
637 if (vertexupdatenum == 0)
640 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
641 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
644 for (i = 0;i < numshadowmarktris;i++)
645 shadowmark[shadowmarktris[i]] = shadowmarkcount;
647 // create the vertices
648 if (projectdirection)
650 for (i = 0;i < numshadowmarktris;i++)
652 element = inelement3i + shadowmarktris[i] * 3;
653 for (j = 0;j < 3;j++)
655 if (vertexupdate[element[j]] != vertexupdatenum)
657 vertexupdate[element[j]] = vertexupdatenum;
658 vertexremap[element[j]] = outvertices;
659 vertex = invertex3f + element[j] * 3;
660 // project one copy of the vertex according to projectvector
661 VectorCopy(vertex, outvertex3f);
662 VectorAdd(vertex, projectvector, (outvertex3f + 3));
671 for (i = 0;i < numshadowmarktris;i++)
673 element = inelement3i + shadowmarktris[i] * 3;
674 for (j = 0;j < 3;j++)
676 if (vertexupdate[element[j]] != vertexupdatenum)
678 vertexupdate[element[j]] = vertexupdatenum;
679 vertexremap[element[j]] = outvertices;
680 vertex = invertex3f + element[j] * 3;
681 // project one copy of the vertex to the sphere radius of the light
682 // (FIXME: would projecting it to the light box be better?)
683 VectorSubtract(vertex, projectorigin, direction);
684 ratio = projectdistance / VectorLength(direction);
685 VectorCopy(vertex, outvertex3f);
686 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
694 if (r_shadow_frontsidecasting.integer)
696 for (i = 0;i < numshadowmarktris;i++)
698 int remappedelement[3];
700 const int *neighbortriangle;
702 markindex = shadowmarktris[i] * 3;
703 element = inelement3i + markindex;
704 neighbortriangle = inneighbor3i + markindex;
705 // output the front and back triangles
706 outelement3i[0] = vertexremap[element[0]];
707 outelement3i[1] = vertexremap[element[1]];
708 outelement3i[2] = vertexremap[element[2]];
709 outelement3i[3] = vertexremap[element[2]] + 1;
710 outelement3i[4] = vertexremap[element[1]] + 1;
711 outelement3i[5] = vertexremap[element[0]] + 1;
715 // output the sides (facing outward from this triangle)
716 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
718 remappedelement[0] = vertexremap[element[0]];
719 remappedelement[1] = vertexremap[element[1]];
720 outelement3i[0] = remappedelement[1];
721 outelement3i[1] = remappedelement[0];
722 outelement3i[2] = remappedelement[0] + 1;
723 outelement3i[3] = remappedelement[1];
724 outelement3i[4] = remappedelement[0] + 1;
725 outelement3i[5] = remappedelement[1] + 1;
730 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
732 remappedelement[1] = vertexremap[element[1]];
733 remappedelement[2] = vertexremap[element[2]];
734 outelement3i[0] = remappedelement[2];
735 outelement3i[1] = remappedelement[1];
736 outelement3i[2] = remappedelement[1] + 1;
737 outelement3i[3] = remappedelement[2];
738 outelement3i[4] = remappedelement[1] + 1;
739 outelement3i[5] = remappedelement[2] + 1;
744 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
746 remappedelement[0] = vertexremap[element[0]];
747 remappedelement[2] = vertexremap[element[2]];
748 outelement3i[0] = remappedelement[0];
749 outelement3i[1] = remappedelement[2];
750 outelement3i[2] = remappedelement[2] + 1;
751 outelement3i[3] = remappedelement[0];
752 outelement3i[4] = remappedelement[2] + 1;
753 outelement3i[5] = remappedelement[0] + 1;
762 for (i = 0;i < numshadowmarktris;i++)
764 int remappedelement[3];
766 const int *neighbortriangle;
768 markindex = shadowmarktris[i] * 3;
769 element = inelement3i + markindex;
770 neighbortriangle = inneighbor3i + markindex;
771 // output the front and back triangles
772 outelement3i[0] = vertexremap[element[2]];
773 outelement3i[1] = vertexremap[element[1]];
774 outelement3i[2] = vertexremap[element[0]];
775 outelement3i[3] = vertexremap[element[0]] + 1;
776 outelement3i[4] = vertexremap[element[1]] + 1;
777 outelement3i[5] = vertexremap[element[2]] + 1;
781 // output the sides (facing outward from this triangle)
782 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
784 remappedelement[0] = vertexremap[element[0]];
785 remappedelement[1] = vertexremap[element[1]];
786 outelement3i[0] = remappedelement[0];
787 outelement3i[1] = remappedelement[1];
788 outelement3i[2] = remappedelement[1] + 1;
789 outelement3i[3] = remappedelement[0];
790 outelement3i[4] = remappedelement[1] + 1;
791 outelement3i[5] = remappedelement[0] + 1;
796 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
798 remappedelement[1] = vertexremap[element[1]];
799 remappedelement[2] = vertexremap[element[2]];
800 outelement3i[0] = remappedelement[1];
801 outelement3i[1] = remappedelement[2];
802 outelement3i[2] = remappedelement[2] + 1;
803 outelement3i[3] = remappedelement[1];
804 outelement3i[4] = remappedelement[2] + 1;
805 outelement3i[5] = remappedelement[1] + 1;
810 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
812 remappedelement[0] = vertexremap[element[0]];
813 remappedelement[2] = vertexremap[element[2]];
814 outelement3i[0] = remappedelement[2];
815 outelement3i[1] = remappedelement[0];
816 outelement3i[2] = remappedelement[0] + 1;
817 outelement3i[3] = remappedelement[2];
818 outelement3i[4] = remappedelement[0] + 1;
819 outelement3i[5] = remappedelement[2] + 1;
827 *outnumvertices = outvertices;
831 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)
837 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
839 tend = firsttriangle + numtris;
840 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
842 // surface box entirely inside light box, no box cull
843 if (projectdirection)
845 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
847 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
848 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
849 shadowmarklist[numshadowmark++] = t;
854 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
855 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
856 shadowmarklist[numshadowmark++] = t;
861 // surface box not entirely inside light box, cull each triangle
862 if (projectdirection)
864 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
866 v[0] = invertex3f + e[0] * 3;
867 v[1] = invertex3f + e[1] * 3;
868 v[2] = invertex3f + e[2] * 3;
869 TriangleNormal(v[0], v[1], v[2], normal);
870 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
871 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
872 shadowmarklist[numshadowmark++] = t;
877 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
879 v[0] = invertex3f + e[0] * 3;
880 v[1] = invertex3f + e[1] * 3;
881 v[2] = invertex3f + e[2] * 3;
882 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
883 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
884 shadowmarklist[numshadowmark++] = t;
890 static void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
892 if (r_shadow_compilingrtlight)
894 // if we're compiling an rtlight, capture the mesh
895 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
898 r_refdef.stats.lights_shadowtriangles += numtriangles;
900 R_Mesh_VertexPointer(vertex3f, 0, 0);
901 GL_LockArrays(0, numvertices);
902 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
904 // decrement stencil if backface is behind depthbuffer
905 GL_CullFace(r_refdef.view.cullface_front);
906 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
907 R_Mesh_Draw(0, numvertices, 0, numtriangles, element3i, NULL, 0, 0);
908 // increment stencil if frontface is behind depthbuffer
909 GL_CullFace(r_refdef.view.cullface_back);
910 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
912 R_Mesh_Draw(0, numvertices, 0, numtriangles, element3i, NULL, 0, 0);
917 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)
920 if (projectdistance < 0.1)
922 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
925 if (!numverts || !nummarktris)
927 // make sure shadowelements is big enough for this volume
928 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
929 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
930 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
931 r_refdef.stats.lights_dynamicshadowtriangles += tris;
932 R_Shadow_RenderVolume(outverts, tris, shadowvertex3f, shadowelements);
935 static void R_Shadow_MakeTextures_MakeCorona(void)
939 unsigned char pixels[32][32][4];
940 for (y = 0;y < 32;y++)
942 dy = (y - 15.5f) * (1.0f / 16.0f);
943 for (x = 0;x < 32;x++)
945 dx = (x - 15.5f) * (1.0f / 16.0f);
946 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
947 a = bound(0, a, 255);
951 pixels[y][x][3] = 255;
954 r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE, NULL);
957 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
959 float dist = sqrt(x*x+y*y+z*z);
960 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
961 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
962 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
965 static void R_Shadow_MakeTextures(void)
968 float intensity, dist;
970 R_FreeTexturePool(&r_shadow_texturepool);
971 r_shadow_texturepool = R_AllocTexturePool();
972 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
973 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
974 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
975 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
976 for (x = 0;x <= ATTENTABLESIZE;x++)
978 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
979 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
980 r_shadow_attentable[x] = bound(0, intensity, 1);
982 // 1D gradient texture
983 for (x = 0;x < ATTEN1DSIZE;x++)
984 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
985 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
987 for (y = 0;y < ATTEN2DSIZE;y++)
988 for (x = 0;x < ATTEN2DSIZE;x++)
989 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);
990 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
992 if (r_shadow_texture3d.integer && gl_texture3d)
994 for (z = 0;z < ATTEN3DSIZE;z++)
995 for (y = 0;y < ATTEN3DSIZE;y++)
996 for (x = 0;x < ATTEN3DSIZE;x++)
997 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));
998 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1001 r_shadow_attenuation3dtexture = NULL;
1004 R_Shadow_MakeTextures_MakeCorona();
1006 // Editor light sprites
1007 r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
1008 r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
1009 r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
1010 r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
1011 r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
1012 r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
1015 void R_Shadow_ValidateCvars(void)
1017 if (r_shadow_texture3d.integer && !gl_texture3d)
1018 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1019 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1020 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1021 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1022 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1025 void R_Shadow_RenderMode_Begin(void)
1027 R_Shadow_ValidateCvars();
1029 if (!r_shadow_attenuation2dtexture
1030 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1031 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1032 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1033 R_Shadow_MakeTextures();
1036 R_Mesh_ColorPointer(NULL, 0, 0);
1037 R_Mesh_ResetTextureState();
1038 GL_BlendFunc(GL_ONE, GL_ZERO);
1039 GL_DepthRange(0, 1);
1040 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1042 GL_DepthMask(false);
1043 GL_Color(0, 0, 0, 1);
1044 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
1046 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1048 if (gl_ext_separatestencil.integer)
1049 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
1050 else if (gl_ext_stenciltwoside.integer)
1051 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
1053 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
1055 if (r_glsl.integer && gl_support_fragment_shader)
1056 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1057 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1058 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1060 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1063 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1065 rsurface.rtlight = rtlight;
1068 void R_Shadow_RenderMode_Reset(void)
1071 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1073 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1075 R_Mesh_ColorPointer(NULL, 0, 0);
1076 R_Mesh_ResetTextureState();
1077 GL_DepthRange(0, 1);
1079 GL_DepthMask(false);
1080 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1081 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1082 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1083 qglStencilMask(~0);CHECKGLERROR
1084 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1085 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1086 GL_CullFace(r_refdef.view.cullface_back);
1087 GL_Color(1, 1, 1, 1);
1088 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1089 GL_BlendFunc(GL_ONE, GL_ZERO);
1090 R_SetupGenericShader(false);
1093 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean clearstencil)
1096 R_Shadow_RenderMode_Reset();
1097 GL_ColorMask(0, 0, 0, 0);
1098 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1099 R_SetupDepthOrShadowShader();
1100 qglDepthFunc(GL_LESS);CHECKGLERROR
1101 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1102 r_shadow_rendermode = r_shadow_shadowingrendermode;
1103 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SEPARATESTENCIL)
1105 GL_CullFace(GL_NONE);
1106 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1107 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1109 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1111 GL_CullFace(GL_NONE);
1112 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1113 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1114 qglStencilMask(~0);CHECKGLERROR
1115 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1116 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1117 qglStencilMask(~0);CHECKGLERROR
1118 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1121 GL_Clear(GL_STENCIL_BUFFER_BIT);
1122 r_refdef.stats.lights_clears++;
1125 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
1128 R_Shadow_RenderMode_Reset();
1129 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1132 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1136 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1137 // only draw light where this geometry was already rendered AND the
1138 // stencil is 128 (values other than this mean shadow)
1139 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1141 r_shadow_rendermode = r_shadow_lightingrendermode;
1142 // do global setup needed for the chosen lighting mode
1143 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1145 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
1146 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1148 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
1149 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
1150 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1153 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1156 R_Shadow_RenderMode_Reset();
1157 GL_BlendFunc(GL_ONE, GL_ONE);
1158 GL_DepthRange(0, 1);
1159 GL_DepthTest(r_showshadowvolumes.integer < 2);
1160 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
1161 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1162 GL_CullFace(GL_NONE);
1163 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1166 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1169 R_Shadow_RenderMode_Reset();
1170 GL_BlendFunc(GL_ONE, GL_ONE);
1171 GL_DepthRange(0, 1);
1172 GL_DepthTest(r_showlighting.integer < 2);
1173 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
1176 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1180 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1181 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1183 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1186 void R_Shadow_RenderMode_End(void)
1189 R_Shadow_RenderMode_Reset();
1190 R_Shadow_RenderMode_ActiveLight(NULL);
1192 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
1193 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1196 int bboxedges[12][2] =
1215 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1217 int i, ix1, iy1, ix2, iy2;
1218 float x1, y1, x2, y2;
1220 float vertex[20][3];
1229 if (!r_shadow_scissor.integer)
1232 // if view is inside the light box, just say yes it's visible
1233 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
1235 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
1239 x1 = y1 = x2 = y2 = 0;
1241 // transform all corners that are infront of the nearclip plane
1242 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
1243 plane4f[3] = r_refdef.view.frustum[4].dist;
1245 for (i = 0;i < 8;i++)
1247 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
1248 dist[i] = DotProduct4(corner[i], plane4f);
1249 sign[i] = dist[i] > 0;
1252 VectorCopy(corner[i], vertex[numvertices]);
1256 // if some points are behind the nearclip, add clipped edge points to make
1257 // sure that the scissor boundary is complete
1258 if (numvertices > 0 && numvertices < 8)
1260 // add clipped edge points
1261 for (i = 0;i < 12;i++)
1263 j = bboxedges[i][0];
1264 k = bboxedges[i][1];
1265 if (sign[j] != sign[k])
1267 f = dist[j] / (dist[j] - dist[k]);
1268 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
1274 // if we have no points to check, the light is behind the view plane
1278 // if we have some points to transform, check what screen area is covered
1279 x1 = y1 = x2 = y2 = 0;
1281 //Con_Printf("%i vertices to transform...\n", numvertices);
1282 for (i = 0;i < numvertices;i++)
1284 VectorCopy(vertex[i], v);
1285 GL_TransformToScreen(v, v2);
1286 //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]);
1289 if (x1 > v2[0]) x1 = v2[0];
1290 if (x2 < v2[0]) x2 = v2[0];
1291 if (y1 > v2[1]) y1 = v2[1];
1292 if (y2 < v2[1]) y2 = v2[1];
1301 // now convert the scissor rectangle to integer screen coordinates
1302 ix1 = (int)(x1 - 1.0f);
1303 iy1 = (int)(y1 - 1.0f);
1304 ix2 = (int)(x2 + 1.0f);
1305 iy2 = (int)(y2 + 1.0f);
1306 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1308 // clamp it to the screen
1309 if (ix1 < r_refdef.view.x) ix1 = r_refdef.view.x;
1310 if (iy1 < r_refdef.view.y) iy1 = r_refdef.view.y;
1311 if (ix2 > r_refdef.view.x + r_refdef.view.width) ix2 = r_refdef.view.x + r_refdef.view.width;
1312 if (iy2 > r_refdef.view.y + r_refdef.view.height) iy2 = r_refdef.view.y + r_refdef.view.height;
1314 // if it is inside out, it's not visible
1315 if (ix2 <= ix1 || iy2 <= iy1)
1318 // the light area is visible, set up the scissor rectangle
1319 GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1320 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1321 //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1322 r_refdef.stats.lights_scissored++;
1326 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1328 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1329 float *normal3f = rsurface.normal3f + 3 * firstvertex;
1330 float *color4f = rsurface.array_color4f + 4 * firstvertex;
1331 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1332 if (r_textureunits.integer >= 3)
1334 if (VectorLength2(diffusecolor) > 0)
1336 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1338 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1339 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1340 if ((dot = DotProduct(n, v)) < 0)
1342 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1343 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1346 VectorCopy(ambientcolor, color4f);
1347 if (r_refdef.fogenabled)
1350 f = FogPoint_Model(vertex3f);
1351 VectorScale(color4f, f, color4f);
1358 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1360 VectorCopy(ambientcolor, color4f);
1361 if (r_refdef.fogenabled)
1364 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1365 f = FogPoint_Model(vertex3f);
1366 VectorScale(color4f, f, color4f);
1372 else if (r_textureunits.integer >= 2)
1374 if (VectorLength2(diffusecolor) > 0)
1376 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1378 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1379 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1381 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1382 if ((dot = DotProduct(n, v)) < 0)
1384 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1385 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1386 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1387 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1391 color4f[0] = ambientcolor[0] * distintensity;
1392 color4f[1] = ambientcolor[1] * distintensity;
1393 color4f[2] = ambientcolor[2] * distintensity;
1395 if (r_refdef.fogenabled)
1398 f = FogPoint_Model(vertex3f);
1399 VectorScale(color4f, f, color4f);
1403 VectorClear(color4f);
1409 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1411 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1412 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1414 color4f[0] = ambientcolor[0] * distintensity;
1415 color4f[1] = ambientcolor[1] * distintensity;
1416 color4f[2] = ambientcolor[2] * distintensity;
1417 if (r_refdef.fogenabled)
1420 f = FogPoint_Model(vertex3f);
1421 VectorScale(color4f, f, color4f);
1425 VectorClear(color4f);
1432 if (VectorLength2(diffusecolor) > 0)
1434 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1436 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1437 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1439 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1440 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1441 if ((dot = DotProduct(n, v)) < 0)
1443 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1444 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1445 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1446 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1450 color4f[0] = ambientcolor[0] * distintensity;
1451 color4f[1] = ambientcolor[1] * distintensity;
1452 color4f[2] = ambientcolor[2] * distintensity;
1454 if (r_refdef.fogenabled)
1457 f = FogPoint_Model(vertex3f);
1458 VectorScale(color4f, f, color4f);
1462 VectorClear(color4f);
1468 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1470 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1471 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1473 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1474 color4f[0] = ambientcolor[0] * distintensity;
1475 color4f[1] = ambientcolor[1] * distintensity;
1476 color4f[2] = ambientcolor[2] * distintensity;
1477 if (r_refdef.fogenabled)
1480 f = FogPoint_Model(vertex3f);
1481 VectorScale(color4f, f, color4f);
1485 VectorClear(color4f);
1492 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1494 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1497 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1498 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1499 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1500 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1501 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1503 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1505 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1506 // the cubemap normalizes this for us
1507 out3f[0] = DotProduct(svector3f, lightdir);
1508 out3f[1] = DotProduct(tvector3f, lightdir);
1509 out3f[2] = DotProduct(normal3f, lightdir);
1513 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1516 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1517 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1518 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1519 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1520 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1521 float lightdir[3], eyedir[3], halfdir[3];
1522 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1524 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1525 VectorNormalize(lightdir);
1526 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
1527 VectorNormalize(eyedir);
1528 VectorAdd(lightdir, eyedir, halfdir);
1529 // the cubemap normalizes this for us
1530 out3f[0] = DotProduct(svector3f, halfdir);
1531 out3f[1] = DotProduct(tvector3f, halfdir);
1532 out3f[2] = DotProduct(normal3f, halfdir);
1536 static void R_Shadow_RenderLighting_VisibleLighting(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, 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)
1538 // used to display how many times a surface is lit for level design purposes
1539 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1542 static void R_Shadow_RenderLighting_Light_GLSL(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, 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)
1544 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1545 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
1546 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
1547 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
1549 R_Mesh_ColorPointer(NULL, 0, 0);
1550 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
1551 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
1552 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
1553 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
1554 if (rsurface.texture->backgroundcurrentskinframe)
1556 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
1557 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
1558 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
1560 //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
1561 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
1562 if(rsurface.texture->colormapping)
1564 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
1565 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
1567 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
1568 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
1569 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
1570 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
1571 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
1572 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1574 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1576 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1577 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1579 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1583 static void R_Shadow_RenderLighting_Light_Dot3_Finalize(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, float r, float g, float b)
1585 // shared final code for all the dot3 layers
1587 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1588 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1590 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1591 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1595 static void R_Shadow_RenderLighting_Light_Dot3_AmbientPass(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
1598 // colorscale accounts for how much we multiply the brightness
1601 // mult is how many times the final pass of the lighting will be
1602 // performed to get more brightness than otherwise possible.
1604 // Limit mult to 64 for sanity sake.
1606 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1608 // 3 3D combine path (Geforce3, Radeon 8500)
1609 memset(&m, 0, sizeof(m));
1610 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1611 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1612 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1613 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1614 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1615 m.tex[1] = R_GetTexture(basetexture);
1616 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1617 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1618 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1619 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1620 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
1621 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1622 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1623 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1624 m.texmatrix[2] = rsurface.entitytolight;
1625 GL_BlendFunc(GL_ONE, GL_ONE);
1627 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1629 // 2 3D combine path (Geforce3, original Radeon)
1630 memset(&m, 0, sizeof(m));
1631 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1632 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1633 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1634 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1635 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1636 m.tex[1] = R_GetTexture(basetexture);
1637 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1638 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1639 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1640 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1641 GL_BlendFunc(GL_ONE, GL_ONE);
1643 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1645 // 4 2D combine path (Geforce3, Radeon 8500)
1646 memset(&m, 0, sizeof(m));
1647 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1648 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1649 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1650 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1651 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1652 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1653 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1654 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1655 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1656 m.texmatrix[1] = rsurface.entitytoattenuationz;
1657 m.tex[2] = R_GetTexture(basetexture);
1658 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1659 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1660 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1661 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1662 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1664 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
1665 m.pointer_texcoord3f[3] = rsurface.vertex3f;
1666 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
1667 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
1668 m.texmatrix[3] = rsurface.entitytolight;
1670 GL_BlendFunc(GL_ONE, GL_ONE);
1672 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1674 // 3 2D combine path (Geforce3, original Radeon)
1675 memset(&m, 0, sizeof(m));
1676 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1677 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1678 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1679 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1680 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1681 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1682 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1683 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1684 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1685 m.texmatrix[1] = rsurface.entitytoattenuationz;
1686 m.tex[2] = R_GetTexture(basetexture);
1687 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1688 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1689 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1690 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1691 GL_BlendFunc(GL_ONE, GL_ONE);
1695 // 2/2/2 2D combine path (any dot3 card)
1696 memset(&m, 0, sizeof(m));
1697 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1698 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1699 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1700 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1701 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1702 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
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.entitytoattenuationz;
1707 R_Mesh_TextureState(&m);
1708 GL_ColorMask(0,0,0,1);
1709 GL_BlendFunc(GL_ONE, GL_ZERO);
1710 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1713 memset(&m, 0, sizeof(m));
1714 m.tex[0] = R_GetTexture(basetexture);
1715 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1716 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1717 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1718 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1719 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1721 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1722 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1723 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1724 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1725 m.texmatrix[1] = rsurface.entitytolight;
1727 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1729 // this final code is shared
1730 R_Mesh_TextureState(&m);
1731 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1734 static void R_Shadow_RenderLighting_Light_Dot3_DiffusePass(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, const vec3_t lightcolorbase, rtexture_t *basetexture, rtexture_t *normalmaptexture, float colorscale)
1737 // colorscale accounts for how much we multiply the brightness
1740 // mult is how many times the final pass of the lighting will be
1741 // performed to get more brightness than otherwise possible.
1743 // Limit mult to 64 for sanity sake.
1745 // generate normalization cubemap texcoords
1746 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1747 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1749 // 3/2 3D combine path (Geforce3, Radeon 8500)
1750 memset(&m, 0, sizeof(m));
1751 m.tex[0] = R_GetTexture(normalmaptexture);
1752 m.texcombinergb[0] = GL_REPLACE;
1753 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1754 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1755 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1756 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1757 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1758 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1759 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1760 m.pointer_texcoord_bufferobject[1] = 0;
1761 m.pointer_texcoord_bufferoffset[1] = 0;
1762 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1763 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1764 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1765 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1766 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
1767 R_Mesh_TextureState(&m);
1768 GL_ColorMask(0,0,0,1);
1769 GL_BlendFunc(GL_ONE, GL_ZERO);
1770 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1773 memset(&m, 0, sizeof(m));
1774 m.tex[0] = R_GetTexture(basetexture);
1775 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1776 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1777 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1778 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1779 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1781 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1782 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1783 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1784 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1785 m.texmatrix[1] = rsurface.entitytolight;
1787 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1789 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1791 // 1/2/2 3D combine path (original Radeon)
1792 memset(&m, 0, sizeof(m));
1793 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1794 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1795 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1796 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1797 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1798 R_Mesh_TextureState(&m);
1799 GL_ColorMask(0,0,0,1);
1800 GL_BlendFunc(GL_ONE, GL_ZERO);
1801 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1804 memset(&m, 0, sizeof(m));
1805 m.tex[0] = R_GetTexture(normalmaptexture);
1806 m.texcombinergb[0] = GL_REPLACE;
1807 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1808 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1809 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1810 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1811 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1812 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1813 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1814 m.pointer_texcoord_bufferobject[1] = 0;
1815 m.pointer_texcoord_bufferoffset[1] = 0;
1816 R_Mesh_TextureState(&m);
1817 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1818 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1821 memset(&m, 0, sizeof(m));
1822 m.tex[0] = R_GetTexture(basetexture);
1823 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1824 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1825 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1826 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1827 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1829 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1830 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1831 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1832 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1833 m.texmatrix[1] = rsurface.entitytolight;
1835 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1837 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1839 // 2/2 3D combine path (original Radeon)
1840 memset(&m, 0, sizeof(m));
1841 m.tex[0] = R_GetTexture(normalmaptexture);
1842 m.texcombinergb[0] = GL_REPLACE;
1843 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1844 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1845 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1846 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1847 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1848 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1849 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1850 m.pointer_texcoord_bufferobject[1] = 0;
1851 m.pointer_texcoord_bufferoffset[1] = 0;
1852 R_Mesh_TextureState(&m);
1853 GL_ColorMask(0,0,0,1);
1854 GL_BlendFunc(GL_ONE, GL_ZERO);
1855 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1858 memset(&m, 0, sizeof(m));
1859 m.tex[0] = R_GetTexture(basetexture);
1860 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1861 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1862 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1863 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1864 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1865 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1866 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1867 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1868 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
1869 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1871 else if (r_textureunits.integer >= 4)
1873 // 4/2 2D combine path (Geforce3, Radeon 8500)
1874 memset(&m, 0, sizeof(m));
1875 m.tex[0] = R_GetTexture(normalmaptexture);
1876 m.texcombinergb[0] = GL_REPLACE;
1877 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1878 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1879 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1880 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1881 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1882 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1883 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1884 m.pointer_texcoord_bufferobject[1] = 0;
1885 m.pointer_texcoord_bufferoffset[1] = 0;
1886 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1887 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1888 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1889 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1890 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
1891 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1892 m.pointer_texcoord3f[3] = rsurface.vertex3f;
1893 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
1894 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
1895 m.texmatrix[3] = rsurface.entitytoattenuationz;
1896 R_Mesh_TextureState(&m);
1897 GL_ColorMask(0,0,0,1);
1898 GL_BlendFunc(GL_ONE, GL_ZERO);
1899 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1902 memset(&m, 0, sizeof(m));
1903 m.tex[0] = R_GetTexture(basetexture);
1904 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1905 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1906 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1907 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1908 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1910 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1911 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1912 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1913 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1914 m.texmatrix[1] = rsurface.entitytolight;
1916 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1920 // 2/2/2 2D combine path (any dot3 card)
1921 memset(&m, 0, sizeof(m));
1922 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1923 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1924 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1925 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1926 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1927 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1928 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1929 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1930 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1931 m.texmatrix[1] = rsurface.entitytoattenuationz;
1932 R_Mesh_TextureState(&m);
1933 GL_ColorMask(0,0,0,1);
1934 GL_BlendFunc(GL_ONE, GL_ZERO);
1935 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1938 memset(&m, 0, sizeof(m));
1939 m.tex[0] = R_GetTexture(normalmaptexture);
1940 m.texcombinergb[0] = GL_REPLACE;
1941 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1942 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1943 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1944 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1945 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1946 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1947 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1948 m.pointer_texcoord_bufferobject[1] = 0;
1949 m.pointer_texcoord_bufferoffset[1] = 0;
1950 R_Mesh_TextureState(&m);
1951 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1952 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1955 memset(&m, 0, sizeof(m));
1956 m.tex[0] = R_GetTexture(basetexture);
1957 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1958 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1959 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1960 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1961 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1963 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1964 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1965 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1966 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1967 m.texmatrix[1] = rsurface.entitytolight;
1969 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1971 // this final code is shared
1972 R_Mesh_TextureState(&m);
1973 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1976 static void R_Shadow_RenderLighting_Light_Dot3_SpecularPass(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, const vec3_t lightcolorbase, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale)
1978 float glossexponent;
1980 // FIXME: detect blendsquare!
1981 //if (!gl_support_blendsquare)
1984 // generate normalization cubemap texcoords
1985 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1986 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1988 // 2/0/0/1/2 3D combine blendsquare path
1989 memset(&m, 0, sizeof(m));
1990 m.tex[0] = R_GetTexture(normalmaptexture);
1991 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1992 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1993 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1994 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1995 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1996 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1997 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1998 m.pointer_texcoord_bufferobject[1] = 0;
1999 m.pointer_texcoord_bufferoffset[1] = 0;
2000 R_Mesh_TextureState(&m);
2001 GL_ColorMask(0,0,0,1);
2002 // this squares the result
2003 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2004 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2006 // second and third pass
2007 R_Mesh_ResetTextureState();
2008 // square alpha in framebuffer a few times to make it shiny
2009 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2010 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2011 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2014 memset(&m, 0, sizeof(m));
2015 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2016 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2017 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2018 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2019 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2020 R_Mesh_TextureState(&m);
2021 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2022 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2025 memset(&m, 0, sizeof(m));
2026 m.tex[0] = R_GetTexture(glosstexture);
2027 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2028 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2029 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2030 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2031 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2033 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2034 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2035 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2036 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2037 m.texmatrix[1] = rsurface.entitytolight;
2039 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2041 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2043 // 2/0/0/2 3D combine blendsquare path
2044 memset(&m, 0, sizeof(m));
2045 m.tex[0] = R_GetTexture(normalmaptexture);
2046 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2047 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2048 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2049 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2050 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2051 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2052 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2053 m.pointer_texcoord_bufferobject[1] = 0;
2054 m.pointer_texcoord_bufferoffset[1] = 0;
2055 R_Mesh_TextureState(&m);
2056 GL_ColorMask(0,0,0,1);
2057 // this squares the result
2058 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2059 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2061 // second and third pass
2062 R_Mesh_ResetTextureState();
2063 // square alpha in framebuffer a few times to make it shiny
2064 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2065 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2066 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2069 memset(&m, 0, sizeof(m));
2070 m.tex[0] = R_GetTexture(glosstexture);
2071 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2072 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2073 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2074 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2075 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2076 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2077 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2078 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2079 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2080 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2084 // 2/0/0/2/2 2D combine blendsquare path
2085 memset(&m, 0, sizeof(m));
2086 m.tex[0] = R_GetTexture(normalmaptexture);
2087 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2088 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2089 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2090 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2091 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2092 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2093 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2094 m.pointer_texcoord_bufferobject[1] = 0;
2095 m.pointer_texcoord_bufferoffset[1] = 0;
2096 R_Mesh_TextureState(&m);
2097 GL_ColorMask(0,0,0,1);
2098 // this squares the result
2099 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2100 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2102 // second and third pass
2103 R_Mesh_ResetTextureState();
2104 // square alpha in framebuffer a few times to make it shiny
2105 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2106 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2107 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2110 memset(&m, 0, sizeof(m));
2111 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2112 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2113 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2114 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2115 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2116 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2117 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2118 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2119 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2120 m.texmatrix[1] = rsurface.entitytoattenuationz;
2121 R_Mesh_TextureState(&m);
2122 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2123 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2126 memset(&m, 0, sizeof(m));
2127 m.tex[0] = R_GetTexture(glosstexture);
2128 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2129 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2130 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2131 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2132 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2134 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2135 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2136 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2137 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2138 m.texmatrix[1] = rsurface.entitytolight;
2140 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2142 // this final code is shared
2143 R_Mesh_TextureState(&m);
2144 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
2147 static void R_Shadow_RenderLighting_Light_Dot3(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, 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)
2149 // ARB path (any Geforce, any Radeon)
2150 qboolean doambient = ambientscale > 0;
2151 qboolean dodiffuse = diffusescale > 0;
2152 qboolean dospecular = specularscale > 0;
2153 if (!doambient && !dodiffuse && !dospecular)
2155 R_Mesh_ColorPointer(NULL, 0, 0);
2157 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
2159 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2163 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
2165 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2170 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
2172 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2175 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
2178 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2185 int newnumtriangles;
2189 int maxtriangles = 4096;
2190 int newelements[4096*3];
2191 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2192 for (renders = 0;renders < 64;renders++)
2197 newnumtriangles = 0;
2199 // due to low fillrate on the cards this vertex lighting path is
2200 // designed for, we manually cull all triangles that do not
2201 // contain a lit vertex
2202 // this builds batches of triangles from multiple surfaces and
2203 // renders them at once
2204 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2206 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2208 if (newnumtriangles)
2210 newfirstvertex = min(newfirstvertex, e[0]);
2211 newlastvertex = max(newlastvertex, e[0]);
2215 newfirstvertex = e[0];
2216 newlastvertex = e[0];
2218 newfirstvertex = min(newfirstvertex, e[1]);
2219 newlastvertex = max(newlastvertex, e[1]);
2220 newfirstvertex = min(newfirstvertex, e[2]);
2221 newlastvertex = max(newlastvertex, e[2]);
2227 if (newnumtriangles >= maxtriangles)
2229 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2230 newnumtriangles = 0;
2236 if (newnumtriangles >= 1)
2238 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2241 // if we couldn't find any lit triangles, exit early
2244 // now reduce the intensity for the next overbright pass
2245 // we have to clamp to 0 here incase the drivers have improper
2246 // handling of negative colors
2247 // (some old drivers even have improper handling of >1 color)
2249 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2251 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2253 c[0] = max(0, c[0] - 1);
2254 c[1] = max(0, c[1] - 1);
2255 c[2] = max(0, c[2] - 1);
2267 static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
2269 // OpenGL 1.1 path (anything)
2270 float ambientcolorbase[3], diffusecolorbase[3];
2271 float ambientcolorpants[3], diffusecolorpants[3];
2272 float ambientcolorshirt[3], diffusecolorshirt[3];
2274 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
2275 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
2276 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
2277 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
2278 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
2279 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
2280 memset(&m, 0, sizeof(m));
2281 m.tex[0] = R_GetTexture(basetexture);
2282 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2283 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2284 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2285 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2286 if (r_textureunits.integer >= 2)
2289 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2290 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2291 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2292 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2293 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2294 if (r_textureunits.integer >= 3)
2296 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2297 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2298 m.texmatrix[2] = rsurface.entitytoattenuationz;
2299 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2300 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2301 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2304 R_Mesh_TextureState(&m);
2305 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2306 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2309 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2310 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2314 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2315 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2319 extern cvar_t gl_lightmaps;
2320 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject)
2322 float ambientscale, diffusescale, specularscale;
2323 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2325 // calculate colors to render this texture with
2326 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2327 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2328 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2329 ambientscale = rsurface.rtlight->ambientscale;
2330 diffusescale = rsurface.rtlight->diffusescale;
2331 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2332 if (!r_shadow_usenormalmap.integer)
2334 ambientscale += 1.0f * diffusescale;
2338 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2340 RSurf_SetupDepthAndCulling();
2341 nmap = rsurface.texture->currentskinframe->nmap;
2342 if (gl_lightmaps.integer)
2343 nmap = r_texture_blanknormalmap;
2344 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
2346 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2347 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2350 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2351 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2352 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2355 VectorClear(lightcolorpants);
2358 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2359 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2360 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2363 VectorClear(lightcolorshirt);
2364 switch (r_shadow_rendermode)
2366 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2367 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2368 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface.texture->basetexture, rsurface.texture->currentskinframe->pants, rsurface.texture->currentskinframe->shirt, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2370 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2371 R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface.texture->basetexture, rsurface.texture->currentskinframe->pants, rsurface.texture->currentskinframe->shirt, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2373 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2374 R_Shadow_RenderLighting_Light_Dot3(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface.texture->basetexture, rsurface.texture->currentskinframe->pants, rsurface.texture->currentskinframe->shirt, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2376 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2377 R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i + firsttriangle * 3, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface.texture->basetexture, rsurface.texture->currentskinframe->pants, rsurface.texture->currentskinframe->shirt, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2380 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2386 switch (r_shadow_rendermode)
2388 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2389 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2390 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, vec3_origin, vec3_origin, rsurface.texture->basetexture, r_texture_black, r_texture_black, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2392 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2393 R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, vec3_origin, vec3_origin, rsurface.texture->basetexture, r_texture_black, r_texture_black, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2395 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2396 R_Shadow_RenderLighting_Light_Dot3(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, vec3_origin, vec3_origin, rsurface.texture->basetexture, r_texture_black, r_texture_black, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2398 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2399 R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i + firsttriangle * 3, lightcolorbase, vec3_origin, vec3_origin, rsurface.texture->basetexture, r_texture_black, r_texture_black, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2402 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2408 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)
2410 matrix4x4_t tempmatrix = *matrix;
2411 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2413 // if this light has been compiled before, free the associated data
2414 R_RTLight_Uncompile(rtlight);
2416 // clear it completely to avoid any lingering data
2417 memset(rtlight, 0, sizeof(*rtlight));
2419 // copy the properties
2420 rtlight->matrix_lighttoworld = tempmatrix;
2421 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2422 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2423 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2424 VectorCopy(color, rtlight->color);
2425 rtlight->cubemapname[0] = 0;
2426 if (cubemapname && cubemapname[0])
2427 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2428 rtlight->shadow = shadow;
2429 rtlight->corona = corona;
2430 rtlight->style = style;
2431 rtlight->isstatic = isstatic;
2432 rtlight->coronasizescale = coronasizescale;
2433 rtlight->ambientscale = ambientscale;
2434 rtlight->diffusescale = diffusescale;
2435 rtlight->specularscale = specularscale;
2436 rtlight->flags = flags;
2438 // compute derived data
2439 //rtlight->cullradius = rtlight->radius;
2440 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2441 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2442 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2443 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2444 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2445 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2446 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2449 // compiles rtlight geometry
2450 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2451 void R_RTLight_Compile(rtlight_t *rtlight)
2454 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2455 int lighttris, shadowtris, shadowmeshes, shadowmeshtris;
2456 entity_render_t *ent = r_refdef.scene.worldentity;
2457 dp_model_t *model = r_refdef.scene.worldmodel;
2458 unsigned char *data;
2460 // compile the light
2461 rtlight->compiled = true;
2462 rtlight->static_numleafs = 0;
2463 rtlight->static_numleafpvsbytes = 0;
2464 rtlight->static_leaflist = NULL;
2465 rtlight->static_leafpvs = NULL;
2466 rtlight->static_numsurfaces = 0;
2467 rtlight->static_surfacelist = NULL;
2468 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2469 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2470 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2471 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2472 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2473 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2475 if (model && model->GetLightInfo)
2477 // this variable must be set for the CompileShadowVolume code
2478 r_shadow_compilingrtlight = rtlight;
2479 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);
2480 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, r_shadow_buffer_visitingleafpvs);
2481 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2482 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2483 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2484 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2485 rtlight->static_numsurfaces = numsurfaces;
2486 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2487 rtlight->static_numleafs = numleafs;
2488 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2489 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2490 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2491 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2492 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2493 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2494 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2495 if (rtlight->static_numsurfaces)
2496 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2497 if (rtlight->static_numleafs)
2498 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2499 if (rtlight->static_numleafpvsbytes)
2500 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2501 if (rtlight->static_numshadowtrispvsbytes)
2502 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2503 if (rtlight->static_numlighttrispvsbytes)
2504 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2505 if (model->CompileShadowVolume && rtlight->shadow)
2506 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2507 // now we're done compiling the rtlight
2508 r_shadow_compilingrtlight = NULL;
2512 // use smallest available cullradius - box radius or light radius
2513 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2514 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2518 if (rtlight->static_meshchain_shadow)
2521 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2524 shadowmeshtris += mesh->numtriangles;
2529 if (rtlight->static_numlighttrispvsbytes)
2530 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2531 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2535 if (rtlight->static_numlighttrispvsbytes)
2536 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2537 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2540 if (developer.integer >= 10)
2541 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);
2544 void R_RTLight_Uncompile(rtlight_t *rtlight)
2546 if (rtlight->compiled)
2548 if (rtlight->static_meshchain_shadow)
2549 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2550 rtlight->static_meshchain_shadow = NULL;
2551 // these allocations are grouped
2552 if (rtlight->static_surfacelist)
2553 Mem_Free(rtlight->static_surfacelist);
2554 rtlight->static_numleafs = 0;
2555 rtlight->static_numleafpvsbytes = 0;
2556 rtlight->static_leaflist = NULL;
2557 rtlight->static_leafpvs = NULL;
2558 rtlight->static_numsurfaces = 0;
2559 rtlight->static_surfacelist = NULL;
2560 rtlight->static_numshadowtrispvsbytes = 0;
2561 rtlight->static_shadowtrispvs = NULL;
2562 rtlight->static_numlighttrispvsbytes = 0;
2563 rtlight->static_lighttrispvs = NULL;
2564 rtlight->compiled = false;
2568 void R_Shadow_UncompileWorldLights(void)
2572 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2573 for (lightindex = 0;lightindex < range;lightindex++)
2575 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2578 R_RTLight_Uncompile(&light->rtlight);
2582 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2586 // reset the count of frustum planes
2587 // see rsurface.rtlight_frustumplanes definition for how much this array
2589 rsurface.rtlight_numfrustumplanes = 0;
2591 // haven't implemented a culling path for ortho rendering
2592 if (!r_refdef.view.useperspective)
2594 // check if the light is on screen and copy the 4 planes if it is
2595 for (i = 0;i < 4;i++)
2596 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2599 for (i = 0;i < 4;i++)
2600 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
2605 // generate a deformed frustum that includes the light origin, this is
2606 // used to cull shadow casting surfaces that can not possibly cast a
2607 // shadow onto the visible light-receiving surfaces, which can be a
2610 // if the light origin is onscreen the result will be 4 planes exactly
2611 // if the light origin is offscreen on only one axis the result will
2612 // be exactly 5 planes (split-side case)
2613 // if the light origin is offscreen on two axes the result will be
2614 // exactly 4 planes (stretched corner case)
2615 for (i = 0;i < 4;i++)
2617 // quickly reject standard frustum planes that put the light
2618 // origin outside the frustum
2619 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2622 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
2624 // if all the standard frustum planes were accepted, the light is onscreen
2625 // otherwise we need to generate some more planes below...
2626 if (rsurface.rtlight_numfrustumplanes < 4)
2628 // at least one of the stock frustum planes failed, so we need to
2629 // create one or two custom planes to enclose the light origin
2630 for (i = 0;i < 4;i++)
2632 // create a plane using the view origin and light origin, and a
2633 // single point from the frustum corner set
2634 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2635 VectorNormalize(plane.normal);
2636 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
2637 // see if this plane is backwards and flip it if so
2638 for (j = 0;j < 4;j++)
2639 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2643 VectorNegate(plane.normal, plane.normal);
2645 // flipped plane, test again to see if it is now valid
2646 for (j = 0;j < 4;j++)
2647 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2649 // if the plane is still not valid, then it is dividing the
2650 // frustum and has to be rejected
2654 // we have created a valid plane, compute extra info
2655 PlaneClassify(&plane);
2657 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2659 // if we've found 5 frustum planes then we have constructed a
2660 // proper split-side case and do not need to keep searching for
2661 // planes to enclose the light origin
2662 if (rsurface.rtlight_numfrustumplanes == 5)
2670 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
2672 plane = rsurface.rtlight_frustumplanes[i];
2673 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_refdef.view.frustumcorner[0], &plane), PlaneDiff(r_refdef.view.frustumcorner[1], &plane), PlaneDiff(r_refdef.view.frustumcorner[2], &plane), PlaneDiff(r_refdef.view.frustumcorner[3], &plane), PlaneDiff(rtlight->shadoworigin, &plane));
2678 // now add the light-space box planes if the light box is rotated, as any
2679 // caster outside the oriented light box is irrelevant (even if it passed
2680 // the worldspace light box, which is axial)
2681 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
2683 for (i = 0;i < 6;i++)
2687 v[i >> 1] = (i & 1) ? -1 : 1;
2688 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
2689 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
2690 plane.dist = VectorNormalizeLength(plane.normal);
2691 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
2692 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2698 // add the world-space reduced box planes
2699 for (i = 0;i < 6;i++)
2701 VectorClear(plane.normal);
2702 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
2703 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
2704 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2713 // reduce all plane distances to tightly fit the rtlight cull box, which
2715 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2716 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2717 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2718 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2719 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2720 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2721 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2722 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2723 oldnum = rsurface.rtlight_numfrustumplanes;
2724 rsurface.rtlight_numfrustumplanes = 0;
2725 for (j = 0;j < oldnum;j++)
2727 // find the nearest point on the box to this plane
2728 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
2729 for (i = 1;i < 8;i++)
2731 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
2732 if (bestdist > dist)
2735 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);
2736 // if the nearest point is near or behind the plane, we want this
2737 // plane, otherwise the plane is useless as it won't cull anything
2738 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
2740 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
2741 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
2748 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2750 RSurf_ActiveWorldEntity();
2751 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2755 for (mesh = rsurface.rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2757 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2758 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
2759 GL_LockArrays(0, mesh->numverts);
2760 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2762 // decrement stencil if backface is behind depthbuffer
2763 GL_CullFace(r_refdef.view.cullface_front);
2764 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2765 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
2766 // increment stencil if frontface is behind depthbuffer
2767 GL_CullFace(r_refdef.view.cullface_back);
2768 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2770 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
2771 GL_LockArrays(0, 0);
2775 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
2778 int surfacelistindex;
2779 msurface_t *surface;
2780 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
2781 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2783 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
2784 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
2785 if (CHECKPVSBIT(trispvs, t))
2786 shadowmarklist[numshadowmark++] = t;
2788 R_Shadow_VolumeFromList(r_refdef.scene.worldmodel->brush.shadowmesh->numverts, r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles, r_refdef.scene.worldmodel->brush.shadowmesh->vertex3f, r_refdef.scene.worldmodel->brush.shadowmesh->element3i, r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius + r_refdef.scene.worldmodel->radius*2 + r_shadow_projectdistance.value, numshadowmark, shadowmarklist);
2790 else if (numsurfaces)
2791 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
2794 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
2796 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2797 vec_t relativeshadowradius;
2798 RSurf_ActiveModelEntity(ent, false, false);
2799 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
2800 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
2801 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2802 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2803 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2804 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2805 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2806 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2807 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2810 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2812 // set up properties for rendering light onto this entity
2813 RSurf_ActiveModelEntity(ent, true, true);
2814 GL_AlphaTest(false);
2815 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
2816 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2817 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2818 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2819 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2820 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2823 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2825 if (!r_refdef.scene.worldmodel->DrawLight)
2828 // set up properties for rendering light onto this entity
2829 RSurf_ActiveWorldEntity();
2830 GL_AlphaTest(false);
2831 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
2832 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2833 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2834 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2835 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2836 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2838 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
2841 void R_Shadow_DrawEntityLight(entity_render_t *ent)
2843 dp_model_t *model = ent->model;
2844 if (!model->DrawLight)
2847 R_Shadow_SetupEntityLight(ent);
2849 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist, NULL);
2852 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2856 int numleafs, numsurfaces;
2857 int *leaflist, *surfacelist;
2858 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
2859 int numlightentities;
2860 int numlightentities_noselfshadow;
2861 int numshadowentities;
2862 int numshadowentities_noselfshadow;
2863 entity_render_t *lightentities[MAX_EDICTS];
2864 entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
2865 entity_render_t *shadowentities[MAX_EDICTS];
2866 entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
2868 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2869 // skip lights that are basically invisible (color 0 0 0)
2870 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2873 // loading is done before visibility checks because loading should happen
2874 // all at once at the start of a level, not when it stalls gameplay.
2875 // (especially important to benchmarks)
2877 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2878 R_RTLight_Compile(rtlight);
2880 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2882 // look up the light style value at this time
2883 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
2884 VectorScale(rtlight->color, f, rtlight->currentcolor);
2886 if (rtlight->selected)
2888 f = 2 + sin(realtime * M_PI * 4.0);
2889 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2893 // if lightstyle is currently off, don't draw the light
2894 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2897 // if the light box is offscreen, skip it
2898 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2901 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
2902 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
2904 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2906 // compiled light, world available and can receive realtime lighting
2907 // retrieve leaf information
2908 numleafs = rtlight->static_numleafs;
2909 leaflist = rtlight->static_leaflist;
2910 leafpvs = rtlight->static_leafpvs;
2911 numsurfaces = rtlight->static_numsurfaces;
2912 surfacelist = rtlight->static_surfacelist;
2913 shadowtrispvs = rtlight->static_shadowtrispvs;
2914 lighttrispvs = rtlight->static_lighttrispvs;
2916 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
2918 // dynamic light, world available and can receive realtime lighting
2919 // calculate lit surfaces and leafs
2920 R_Shadow_EnlargeLeafSurfaceTrisBuffer(r_refdef.scene.worldmodel->brush.num_leafs, r_refdef.scene.worldmodel->num_surfaces, r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles, r_refdef.scene.worldmodel->surfmesh.num_triangles);
2921 r_refdef.scene.worldmodel->GetLightInfo(r_refdef.scene.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, r_shadow_buffer_visitingleafpvs);
2922 leaflist = r_shadow_buffer_leaflist;
2923 leafpvs = r_shadow_buffer_leafpvs;
2924 surfacelist = r_shadow_buffer_surfacelist;
2925 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
2926 lighttrispvs = r_shadow_buffer_lighttrispvs;
2927 // if the reduced leaf bounds are offscreen, skip it
2928 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2939 shadowtrispvs = NULL;
2940 lighttrispvs = NULL;
2942 // check if light is illuminating any visible leafs
2945 for (i = 0;i < numleafs;i++)
2946 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
2951 // set up a scissor rectangle for this light
2952 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2955 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
2957 // make a list of lit entities and shadow casting entities
2958 numlightentities = 0;
2959 numlightentities_noselfshadow = 0;
2960 numshadowentities = 0;
2961 numshadowentities_noselfshadow = 0;
2962 // add dynamic entities that are lit by the light
2963 if (r_drawentities.integer)
2965 for (i = 0;i < r_refdef.scene.numentities;i++)
2968 entity_render_t *ent = r_refdef.scene.entities[i];
2970 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2972 // skip the object entirely if it is not within the valid
2973 // shadow-casting region (which includes the lit region)
2974 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
2976 if (!(model = ent->model))
2978 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
2980 // this entity wants to receive light, is visible, and is
2981 // inside the light box
2982 // TODO: check if the surfaces in the model can receive light
2983 // so now check if it's in a leaf seen by the light
2984 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.scene.worldmodel, leafpvs, ent->mins, ent->maxs))
2986 if (ent->flags & RENDER_NOSELFSHADOW)
2987 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
2989 lightentities[numlightentities++] = ent;
2990 // since it is lit, it probably also casts a shadow...
2991 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2992 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2993 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2995 // note: exterior models without the RENDER_NOSELFSHADOW
2996 // flag still create a RENDER_NOSELFSHADOW shadow but
2997 // are lit normally, this means that they are
2998 // self-shadowing but do not shadow other
2999 // RENDER_NOSELFSHADOW entities such as the gun
3000 // (very weird, but keeps the player shadow off the gun)
3001 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3002 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3004 shadowentities[numshadowentities++] = ent;
3007 else if (ent->flags & RENDER_SHADOW)
3009 // this entity is not receiving light, but may still need to
3011 // TODO: check if the surfaces in the model can cast shadow
3012 // now check if it is in a leaf seen by the light
3013 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.scene.worldmodel, leafpvs, ent->mins, ent->maxs))
3015 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3016 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3017 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3019 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3020 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3022 shadowentities[numshadowentities++] = ent;
3028 // return if there's nothing at all to light
3029 if (!numlightentities && !numsurfaces)
3032 // don't let sound skip if going slow
3033 if (r_refdef.scene.extraupdate)
3036 // make this the active rtlight for rendering purposes
3037 R_Shadow_RenderMode_ActiveLight(rtlight);
3038 // count this light in the r_speeds
3039 r_refdef.stats.lights++;
3041 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3043 // optionally draw visible shape of the shadow volumes
3044 // for performance analysis by level designers
3045 R_Shadow_RenderMode_VisibleShadowVolumes();
3047 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3048 for (i = 0;i < numshadowentities;i++)
3049 R_Shadow_DrawEntityShadow(shadowentities[i]);
3050 for (i = 0;i < numshadowentities_noselfshadow;i++)
3051 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3054 if (gl_stencil && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3056 // draw stencil shadow volumes to mask off pixels that are in shadow
3057 // so that they won't receive lighting
3058 R_Shadow_RenderMode_StencilShadowVolumes(true);
3060 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3061 for (i = 0;i < numshadowentities;i++)
3062 R_Shadow_DrawEntityShadow(shadowentities[i]);
3063 if (numlightentities_noselfshadow)
3065 // draw lighting in the unmasked areas
3066 R_Shadow_RenderMode_Lighting(true, false);
3067 for (i = 0;i < numlightentities_noselfshadow;i++)
3068 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3070 // optionally draw the illuminated areas
3071 // for performance analysis by level designers
3072 if (r_showlighting.integer && r_refdef.view.showdebug)
3074 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3075 for (i = 0;i < numlightentities_noselfshadow;i++)
3076 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3079 R_Shadow_RenderMode_StencilShadowVolumes(false);
3081 for (i = 0;i < numshadowentities_noselfshadow;i++)
3082 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3084 if (numsurfaces + numlightentities)
3086 // draw lighting in the unmasked areas
3087 R_Shadow_RenderMode_Lighting(true, false);
3089 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3090 for (i = 0;i < numlightentities;i++)
3091 R_Shadow_DrawEntityLight(lightentities[i]);
3093 // optionally draw the illuminated areas
3094 // for performance analysis by level designers
3095 if (r_showlighting.integer && r_refdef.view.showdebug)
3097 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3099 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3100 for (i = 0;i < numlightentities;i++)
3101 R_Shadow_DrawEntityLight(lightentities[i]);
3107 if (numsurfaces + numlightentities)
3109 // draw lighting in the unmasked areas
3110 R_Shadow_RenderMode_Lighting(false, false);
3112 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3113 for (i = 0;i < numlightentities;i++)
3114 R_Shadow_DrawEntityLight(lightentities[i]);
3115 for (i = 0;i < numlightentities_noselfshadow;i++)
3116 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3118 // optionally draw the illuminated areas
3119 // for performance analysis by level designers
3120 if (r_showlighting.integer && r_refdef.view.showdebug)
3122 R_Shadow_RenderMode_VisibleLighting(false, false);
3124 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3125 for (i = 0;i < numlightentities;i++)
3126 R_Shadow_DrawEntityLight(lightentities[i]);
3127 for (i = 0;i < numlightentities_noselfshadow;i++)
3128 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3134 void R_Shadow_DrawLightSprites(void);
3135 void R_ShadowVolumeLighting(qboolean visible)
3143 if (r_editlights.integer)
3144 R_Shadow_DrawLightSprites();
3146 R_Shadow_RenderMode_Begin();
3148 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3149 if (r_shadow_debuglight.integer >= 0)
3151 lightindex = r_shadow_debuglight.integer;
3152 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3153 if (light && (light->flags & flag))
3154 R_DrawRTLight(&light->rtlight, visible);
3158 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3159 for (lightindex = 0;lightindex < range;lightindex++)
3161 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3162 if (light && (light->flags & flag))
3163 R_DrawRTLight(&light->rtlight, visible);
3166 if (r_refdef.scene.rtdlight)
3167 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3168 R_DrawRTLight(&r_refdef.scene.lights[lnum], visible);
3170 R_Shadow_RenderMode_End();
3173 extern void R_SetupView(qboolean allowwaterclippingplane);
3174 extern cvar_t r_shadows_throwdistance;
3175 void R_DrawModelShadows(void)
3178 float relativethrowdistance;
3179 entity_render_t *ent;
3180 vec3_t relativelightorigin;
3181 vec3_t relativelightdirection;
3182 vec3_t relativeshadowmins, relativeshadowmaxs;
3185 if (!r_drawentities.integer || !gl_stencil)
3189 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3191 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3193 if (gl_ext_separatestencil.integer)
3194 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
3195 else if (gl_ext_stenciltwoside.integer)
3196 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
3198 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
3200 R_Shadow_RenderMode_StencilShadowVolumes(true);
3202 for (i = 0;i < r_refdef.scene.numentities;i++)
3204 ent = r_refdef.scene.entities[i];
3205 // cast shadows from anything that is not a submodel of the map
3206 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
3208 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3209 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3210 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3211 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3212 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3213 RSurf_ActiveModelEntity(ent, false, false);
3214 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
3218 // not really the right mode, but this will disable any silly stencil features
3219 R_Shadow_RenderMode_VisibleLighting(true, true);
3221 // vertex coordinates for a quad that covers the screen exactly
3222 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
3223 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
3224 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
3225 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
3227 // set up ortho view for rendering this pass
3228 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
3229 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3230 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3231 GL_ScissorTest(true);
3232 R_Mesh_Matrix(&identitymatrix);
3233 R_Mesh_ResetTextureState();
3234 R_Mesh_VertexPointer(vertex3f, 0, 0);
3235 R_Mesh_ColorPointer(NULL, 0, 0);
3237 // set up a 50% darkening blend on shadowed areas
3238 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3239 GL_DepthRange(0, 1);
3240 GL_DepthTest(false);
3241 GL_DepthMask(false);
3242 GL_PolygonOffset(0, 0);CHECKGLERROR
3243 GL_Color(0, 0, 0, 0.5);
3244 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3245 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
3246 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
3247 qglStencilMask(~0);CHECKGLERROR
3248 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3249 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
3251 // apply the blend to the shadowed areas
3252 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
3254 // restoring the perspective view is done by R_RenderScene
3255 //R_SetupView(true);
3257 // restore other state to normal
3258 R_Shadow_RenderMode_End();
3261 void R_DrawCoronas(void)
3264 float cscale, scale;
3269 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
3271 R_Mesh_Matrix(&identitymatrix);
3272 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3273 // FIXME: these traces should scan all render entities instead of cl.world
3274 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3275 for (lightindex = 0;lightindex < range;lightindex++)
3277 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3280 rtlight = &light->rtlight;
3281 if (!(rtlight->flags & flag))
3283 if (rtlight->corona * r_coronas.value <= 0)
3285 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
3287 cscale = rtlight->corona * r_coronas.value* 0.25f;
3288 scale = rtlight->radius * rtlight->coronasizescale;
3289 if (VectorDistance2(rtlight->shadoworigin, r_refdef.view.origin) < 16.0f * 16.0f)
3291 if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
3293 R_DrawSprite(GL_ONE, GL_ONE, r_shadow_lightcorona, NULL, true, false, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, rtlight->color[0] * cscale, rtlight->color[1] * cscale, rtlight->color[2] * cscale, 1);
3295 for (i = 0;i < r_refdef.scene.numlights;i++)
3297 rtlight = &r_refdef.scene.lights[i];
3298 if (!(rtlight->flags & flag))
3300 if (rtlight->corona <= 0)
3302 if (VectorDistance2(rtlight->shadoworigin, r_refdef.view.origin) < 32.0f * 32.0f)
3304 if (gl_flashblend.integer)
3306 cscale = rtlight->corona * 1.0f;
3307 scale = rtlight->radius * rtlight->coronasizescale * 2.0f;
3311 cscale = rtlight->corona * r_coronas.value* 0.25f;
3312 scale = rtlight->radius * rtlight->coronasizescale;
3314 if (VectorLength(rtlight->color) * cscale < (1.0f / 256.0f))
3316 if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
3318 R_DrawSprite(GL_ONE, GL_ONE, r_shadow_lightcorona, NULL, true, false, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, rtlight->color[0] * cscale, rtlight->color[1] * cscale, rtlight->color[2] * cscale, 1);
3324 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3325 typedef struct suffixinfo_s
3328 qboolean flipx, flipy, flipdiagonal;
3331 static suffixinfo_t suffix[3][6] =
3334 {"px", false, false, false},
3335 {"nx", false, false, false},
3336 {"py", false, false, false},
3337 {"ny", false, false, false},
3338 {"pz", false, false, false},
3339 {"nz", false, false, false}
3342 {"posx", false, false, false},
3343 {"negx", false, false, false},
3344 {"posy", false, false, false},
3345 {"negy", false, false, false},
3346 {"posz", false, false, false},
3347 {"negz", false, false, false}
3350 {"rt", true, false, true},
3351 {"lf", false, true, true},
3352 {"ft", true, true, false},
3353 {"bk", false, false, false},
3354 {"up", true, false, true},
3355 {"dn", true, false, true}
3359 static int componentorder[4] = {0, 1, 2, 3};
3361 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3363 int i, j, cubemapsize;
3364 unsigned char *cubemappixels, *image_buffer;
3365 rtexture_t *cubemaptexture;
3367 // must start 0 so the first loadimagepixels has no requested width/height
3369 cubemappixels = NULL;
3370 cubemaptexture = NULL;
3371 // keep trying different suffix groups (posx, px, rt) until one loads
3372 for (j = 0;j < 3 && !cubemappixels;j++)
3374 // load the 6 images in the suffix group
3375 for (i = 0;i < 6;i++)
3377 // generate an image name based on the base and and suffix
3378 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3380 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
3382 // an image loaded, make sure width and height are equal
3383 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
3385 // if this is the first image to load successfully, allocate the cubemap memory
3386 if (!cubemappixels && image_width >= 1)
3388 cubemapsize = image_width;
3389 // note this clears to black, so unavailable sides are black
3390 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3392 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3394 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);
3397 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3399 Mem_Free(image_buffer);
3403 // if a cubemap loaded, upload it
3406 if (developer_loading.integer)
3407 Con_Printf("loading cubemap \"%s\"\n", basename);
3409 if (!r_shadow_filters_texturepool)
3410 r_shadow_filters_texturepool = R_AllocTexturePool();
3411 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0), NULL);
3412 Mem_Free(cubemappixels);
3416 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
3417 if (developer_loading.integer)
3419 Con_Printf("(tried tried images ");
3420 for (j = 0;j < 3;j++)
3421 for (i = 0;i < 6;i++)
3422 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3423 Con_Print(" and was unable to find any of them).\n");
3426 return cubemaptexture;
3429 rtexture_t *R_Shadow_Cubemap(const char *basename)
3432 for (i = 0;i < numcubemaps;i++)
3433 if (!strcasecmp(cubemaps[i].basename, basename))
3434 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
3435 if (i >= MAX_CUBEMAPS)
3436 return r_texture_whitecube;
3438 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
3439 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3440 return cubemaps[i].texture;
3443 void R_Shadow_FreeCubemaps(void)
3446 for (i = 0;i < numcubemaps;i++)
3448 if (developer_loading.integer)
3449 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
3450 if (cubemaps[i].texture)
3451 R_FreeTexture(cubemaps[i].texture);
3455 R_FreeTexturePool(&r_shadow_filters_texturepool);
3458 dlight_t *R_Shadow_NewWorldLight(void)
3460 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
3463 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)
3466 // validate parameters
3467 if (style < 0 || style >= MAX_LIGHTSTYLES)
3469 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3475 // copy to light properties
3476 VectorCopy(origin, light->origin);
3477 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3478 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3479 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3480 light->color[0] = max(color[0], 0);
3481 light->color[1] = max(color[1], 0);
3482 light->color[2] = max(color[2], 0);
3483 light->radius = max(radius, 0);
3484 light->style = style;
3485 light->shadow = shadowenable;
3486 light->corona = corona;
3487 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3488 light->coronasizescale = coronasizescale;
3489 light->ambientscale = ambientscale;
3490 light->diffusescale = diffusescale;
3491 light->specularscale = specularscale;
3492 light->flags = flags;
3494 // update renderable light data
3495 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
3496 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);
3499 void R_Shadow_FreeWorldLight(dlight_t *light)
3501 if (r_shadow_selectedlight == light)
3502 r_shadow_selectedlight = NULL;
3503 R_RTLight_Uncompile(&light->rtlight);
3504 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
3507 void R_Shadow_ClearWorldLights(void)
3511 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3512 for (lightindex = 0;lightindex < range;lightindex++)
3514 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3516 R_Shadow_FreeWorldLight(light);
3518 r_shadow_selectedlight = NULL;
3519 R_Shadow_FreeCubemaps();
3522 void R_Shadow_SelectLight(dlight_t *light)
3524 if (r_shadow_selectedlight)
3525 r_shadow_selectedlight->selected = false;
3526 r_shadow_selectedlight = light;
3527 if (r_shadow_selectedlight)
3528 r_shadow_selectedlight->selected = true;
3531 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3533 // this is never batched (there can be only one)
3534 R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, r_editlights_sprcursor->tex, r_editlights_sprcursor->tex, false, false, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE, 1, 1, 1, 1);
3537 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3544 // this is never batched (due to the ent parameter changing every time)
3545 // so numsurfaces == 1 and surfacelist[0] == lightnumber
3546 const dlight_t *light = (dlight_t *)ent;
3549 VectorScale(light->color, intensity, spritecolor);
3550 if (VectorLength(spritecolor) < 0.1732f)
3551 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
3552 if (VectorLength(spritecolor) > 1.0f)
3553 VectorNormalize(spritecolor);
3555 // draw light sprite
3556 if (light->cubemapname[0] && !light->shadow)
3557 pic = r_editlights_sprcubemapnoshadowlight;
3558 else if (light->cubemapname[0])
3559 pic = r_editlights_sprcubemaplight;
3560 else if (!light->shadow)
3561 pic = r_editlights_sprnoshadowlight;
3563 pic = r_editlights_sprlight;
3564 R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, pic->tex, pic->tex, false, false, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s, spritecolor[0], spritecolor[1], spritecolor[2], 1);
3565 // draw selection sprite if light is selected
3566 if (light->selected)
3567 R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, r_editlights_sprselection->tex, r_editlights_sprselection->tex, false, false, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s, 1, 1, 1, 1);
3568 // VorteX todo: add normalmode/realtime mode light overlay sprites?
3571 void R_Shadow_DrawLightSprites(void)
3575 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3576 for (lightindex = 0;lightindex < range;lightindex++)
3578 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3580 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
3582 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
3585 void R_Shadow_SelectLightInView(void)
3587 float bestrating, rating, temp[3];
3591 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3594 for (lightindex = 0;lightindex < range;lightindex++)
3596 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3599 VectorSubtract(light->origin, r_refdef.view.origin, temp);
3600 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
3603 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3604 if (bestrating < rating && CL_Move(light->origin, vec3_origin, vec3_origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
3606 bestrating = rating;
3611 R_Shadow_SelectLight(best);
3614 void R_Shadow_LoadWorldLights(void)
3616 int n, a, style, shadow, flags;
3617 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3618 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3619 if (cl.worldmodel == NULL)
3621 Con_Print("No map loaded.\n");
3624 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
3625 strlcat (name, ".rtlights", sizeof (name));
3626 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3636 for (;COM_Parse(t, true) && strcmp(
3637 if (COM_Parse(t, true))
3639 if (com_token[0] == '!')
3642 origin[0] = atof(com_token+1);
3645 origin[0] = atof(com_token);
3650 while (*s && *s != '\n' && *s != '\r')
3656 // check for modifier flags
3663 #if _MSC_VER >= 1400
3664 #define sscanf sscanf_s
3666 cubemapname[sizeof(cubemapname)-1] = 0;
3667 #if MAX_QPATH != 128
3668 #error update this code if MAX_QPATH changes
3670 a = sscanf(t, "%f %f %f %f %f %f %f %d %127s %f %f %f %f %f %f %f %f %i", &origin[0], &origin[1], &origin[2], &radius, &color[0], &color[1], &color[2], &style, cubemapname
3671 #if _MSC_VER >= 1400
3672 , sizeof(cubemapname)
3674 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
3677 flags = LIGHTFLAG_REALTIMEMODE;
3685 coronasizescale = 0.25f;
3687 VectorClear(angles);
3690 if (a < 9 || !strcmp(cubemapname, "\"\""))
3692 // remove quotes on cubemapname
3693 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3696 namelen = strlen(cubemapname) - 2;
3697 memmove(cubemapname, cubemapname + 1, namelen);
3698 cubemapname[namelen] = '\0';
3702 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);
3705 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3713 Con_Printf("invalid rtlights file \"%s\"\n", name);
3714 Mem_Free(lightsstring);
3718 void R_Shadow_SaveWorldLights(void)
3722 size_t bufchars, bufmaxchars;
3724 char name[MAX_QPATH];
3725 char line[MAX_INPUTLINE];
3726 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
3727 // I hate lines which are 3 times my screen size :( --blub
3730 if (cl.worldmodel == NULL)
3732 Con_Print("No map loaded.\n");
3735 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
3736 strlcat (name, ".rtlights", sizeof (name));
3737 bufchars = bufmaxchars = 0;
3739 for (lightindex = 0;lightindex < range;lightindex++)
3741 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3744 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3745 dpsnprintf(line, sizeof(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);
3746 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3747 dpsnprintf(line, sizeof(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]);
3749 dpsnprintf(line, sizeof(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);
3750 if (bufchars + strlen(line) > bufmaxchars)
3752 bufmaxchars = bufchars + strlen(line) + 2048;
3754 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3758 memcpy(buf, oldbuf, bufchars);
3764 memcpy(buf + bufchars, line, strlen(line));
3765 bufchars += strlen(line);
3769 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3774 void R_Shadow_LoadLightsFile(void)
3777 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3778 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3779 if (cl.worldmodel == NULL)
3781 Con_Print("No map loaded.\n");
3784 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
3785 strlcat (name, ".lights", sizeof (name));
3786 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3794 while (*s && *s != '\n' && *s != '\r')
3800 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);
3804 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);
3807 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3808 radius = bound(15, radius, 4096);
3809 VectorScale(color, (2.0f / (8388608.0f)), color);
3810 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3818 Con_Printf("invalid lights file \"%s\"\n", name);
3819 Mem_Free(lightsstring);
3823 // tyrlite/hmap2 light types in the delay field
3824 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3826 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3828 int entnum, style, islight, skin, pflags, effects, type, n;
3831 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3832 char key[256], value[MAX_INPUTLINE];
3834 if (cl.worldmodel == NULL)
3836 Con_Print("No map loaded.\n");
3839 // try to load a .ent file first
3840 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
3841 strlcat (key, ".ent", sizeof (key));
3842 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3843 // and if that is not found, fall back to the bsp file entity string
3845 data = cl.worldmodel->brush.entities;
3848 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
3850 type = LIGHTTYPE_MINUSX;
3851 origin[0] = origin[1] = origin[2] = 0;
3852 originhack[0] = originhack[1] = originhack[2] = 0;
3853 angles[0] = angles[1] = angles[2] = 0;
3854 color[0] = color[1] = color[2] = 1;
3855 light[0] = light[1] = light[2] = 1;light[3] = 300;
3856 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3866 if (!COM_ParseToken_Simple(&data, false, false))
3868 if (com_token[0] == '}')
3869 break; // end of entity
3870 if (com_token[0] == '_')
3871 strlcpy(key, com_token + 1, sizeof(key));
3873 strlcpy(key, com_token, sizeof(key));
3874 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3875 key[strlen(key)-1] = 0;
3876 if (!COM_ParseToken_Simple(&data, false, false))
3878 strlcpy(value, com_token, sizeof(value));
3880 // now that we have the key pair worked out...
3881 if (!strcmp("light", key))
3883 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3887 light[0] = vec[0] * (1.0f / 256.0f);
3888 light[1] = vec[0] * (1.0f / 256.0f);
3889 light[2] = vec[0] * (1.0f / 256.0f);
3895 light[0] = vec[0] * (1.0f / 255.0f);
3896 light[1] = vec[1] * (1.0f / 255.0f);
3897 light[2] = vec[2] * (1.0f / 255.0f);
3901 else if (!strcmp("delay", key))
3903 else if (!strcmp("origin", key))
3904 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3905 else if (!strcmp("angle", key))
3906 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3907 else if (!strcmp("angles", key))
3908 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3909 else if (!strcmp("color", key))
3910 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3911 else if (!strcmp("wait", key))
3912 fadescale = atof(value);
3913 else if (!strcmp("classname", key))
3915 if (!strncmp(value, "light", 5))
3918 if (!strcmp(value, "light_fluoro"))
3923 overridecolor[0] = 1;
3924 overridecolor[1] = 1;
3925 overridecolor[2] = 1;
3927 if (!strcmp(value, "light_fluorospark"))
3932 overridecolor[0] = 1;
3933 overridecolor[1] = 1;
3934 overridecolor[2] = 1;
3936 if (!strcmp(value, "light_globe"))
3941 overridecolor[0] = 1;
3942 overridecolor[1] = 0.8;
3943 overridecolor[2] = 0.4;
3945 if (!strcmp(value, "light_flame_large_yellow"))
3950 overridecolor[0] = 1;
3951 overridecolor[1] = 0.5;
3952 overridecolor[2] = 0.1;
3954 if (!strcmp(value, "light_flame_small_yellow"))
3959 overridecolor[0] = 1;
3960 overridecolor[1] = 0.5;
3961 overridecolor[2] = 0.1;
3963 if (!strcmp(value, "light_torch_small_white"))
3968 overridecolor[0] = 1;
3969 overridecolor[1] = 0.5;
3970 overridecolor[2] = 0.1;
3972 if (!strcmp(value, "light_torch_small_walltorch"))
3977 overridecolor[0] = 1;
3978 overridecolor[1] = 0.5;
3979 overridecolor[2] = 0.1;
3983 else if (!strcmp("style", key))
3984 style = atoi(value);
3985 else if (!strcmp("skin", key))
3986 skin = (int)atof(value);
3987 else if (!strcmp("pflags", key))
3988 pflags = (int)atof(value);
3989 else if (!strcmp("effects", key))
3990 effects = (int)atof(value);
3991 else if (cl.worldmodel->type == mod_brushq3)
3993 if (!strcmp("scale", key))
3994 lightscale = atof(value);
3995 if (!strcmp("fade", key))
3996 fadescale = atof(value);
4001 if (lightscale <= 0)
4005 if (color[0] == color[1] && color[0] == color[2])
4007 color[0] *= overridecolor[0];
4008 color[1] *= overridecolor[1];
4009 color[2] *= overridecolor[2];
4011 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
4012 color[0] = color[0] * light[0];
4013 color[1] = color[1] * light[1];
4014 color[2] = color[2] * light[2];
4017 case LIGHTTYPE_MINUSX:
4019 case LIGHTTYPE_RECIPX:
4021 VectorScale(color, (1.0f / 16.0f), color);
4023 case LIGHTTYPE_RECIPXX:
4025 VectorScale(color, (1.0f / 16.0f), color);
4028 case LIGHTTYPE_NONE:
4032 case LIGHTTYPE_MINUSXX:
4035 VectorAdd(origin, originhack, origin);
4037 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);
4040 Mem_Free(entfiledata);
4044 void R_Shadow_SetCursorLocationForView(void)
4047 vec3_t dest, endpos;
4049 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
4050 trace = CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
4051 if (trace.fraction < 1)
4053 dist = trace.fraction * r_editlights_cursordistance.value;
4054 push = r_editlights_cursorpushback.value;
4058 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
4059 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
4063 VectorClear( endpos );
4065 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4066 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4067 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4070 void R_Shadow_UpdateWorldLightSelection(void)
4072 if (r_editlights.integer)
4074 R_Shadow_SetCursorLocationForView();
4075 R_Shadow_SelectLightInView();
4078 R_Shadow_SelectLight(NULL);
4081 void R_Shadow_EditLights_Clear_f(void)
4083 R_Shadow_ClearWorldLights();
4086 void R_Shadow_EditLights_Reload_f(void)
4090 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
4091 R_Shadow_ClearWorldLights();
4092 R_Shadow_LoadWorldLights();
4093 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4095 R_Shadow_LoadLightsFile();
4096 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4097 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4101 void R_Shadow_EditLights_Save_f(void)
4105 R_Shadow_SaveWorldLights();
4108 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
4110 R_Shadow_ClearWorldLights();
4111 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4114 void R_Shadow_EditLights_ImportLightsFile_f(void)
4116 R_Shadow_ClearWorldLights();
4117 R_Shadow_LoadLightsFile();
4120 void R_Shadow_EditLights_Spawn_f(void)
4123 if (!r_editlights.integer)
4125 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4128 if (Cmd_Argc() != 1)
4130 Con_Print("r_editlights_spawn does not take parameters\n");
4133 color[0] = color[1] = color[2] = 1;
4134 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4137 void R_Shadow_EditLights_Edit_f(void)
4139 vec3_t origin, angles, color;
4140 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
4141 int style, shadows, flags, normalmode, realtimemode;
4142 char cubemapname[MAX_INPUTLINE];
4143 if (!r_editlights.integer)
4145 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4148 if (!r_shadow_selectedlight)
4150 Con_Print("No selected light.\n");
4153 VectorCopy(r_shadow_selectedlight->origin, origin);
4154 VectorCopy(r_shadow_selectedlight->angles, angles);
4155 VectorCopy(r_shadow_selectedlight->color, color);
4156 radius = r_shadow_selectedlight->radius;
4157 style = r_shadow_selectedlight->style;
4158 if (r_shadow_selectedlight->cubemapname)
4159 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
4162 shadows = r_shadow_selectedlight->shadow;
4163 corona = r_shadow_selectedlight->corona;
4164 coronasizescale = r_shadow_selectedlight->coronasizescale;
4165 ambientscale = r_shadow_selectedlight->ambientscale;
4166 diffusescale = r_shadow_selectedlight->diffusescale;
4167 specularscale = r_shadow_selectedlight->specularscale;
4168 flags = r_shadow_selectedlight->flags;
4169 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
4170 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
4171 if (!strcmp(Cmd_Argv(1), "origin"))
4173 if (Cmd_Argc() != 5)
4175 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4178 origin[0] = atof(Cmd_Argv(2));
4179 origin[1] = atof(Cmd_Argv(3));
4180 origin[2] = atof(Cmd_Argv(4));
4182 else if (!strcmp(Cmd_Argv(1), "originx"))
4184 if (Cmd_Argc() != 3)
4186 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4189 origin[0] = atof(Cmd_Argv(2));
4191 else if (!strcmp(Cmd_Argv(1), "originy"))
4193 if (Cmd_Argc() != 3)
4195 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4198 origin[1] = atof(Cmd_Argv(2));
4200 else if (!strcmp(Cmd_Argv(1), "originz"))
4202 if (Cmd_Argc() != 3)
4204 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4207 origin[2] = atof(Cmd_Argv(2));
4209 else if (!strcmp(Cmd_Argv(1), "move"))
4211 if (Cmd_Argc() != 5)
4213 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4216 origin[0] += atof(Cmd_Argv(2));
4217 origin[1] += atof(Cmd_Argv(3));
4218 origin[2] += atof(Cmd_Argv(4));
4220 else if (!strcmp(Cmd_Argv(1), "movex"))
4222 if (Cmd_Argc() != 3)
4224 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4227 origin[0] += atof(Cmd_Argv(2));
4229 else if (!strcmp(Cmd_Argv(1), "movey"))
4231 if (Cmd_Argc() != 3)
4233 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4236 origin[1] += atof(Cmd_Argv(2));
4238 else if (!strcmp(Cmd_Argv(1), "movez"))
4240 if (Cmd_Argc() != 3)
4242 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4245 origin[2] += atof(Cmd_Argv(2));
4247 else if (!strcmp(Cmd_Argv(1), "angles"))
4249 if (Cmd_Argc() != 5)
4251 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4254 angles[0] = atof(Cmd_Argv(2));
4255 angles[1] = atof(Cmd_Argv(3));
4256 angles[2] = atof(Cmd_Argv(4));
4258 else if (!strcmp(Cmd_Argv(1), "anglesx"))
4260 if (Cmd_Argc() != 3)
4262 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4265 angles[0] = atof(Cmd_Argv(2));
4267 else if (!strcmp(Cmd_Argv(1), "anglesy"))
4269 if (Cmd_Argc() != 3)
4271 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4274 angles[1] = atof(Cmd_Argv(2));
4276 else if (!strcmp(Cmd_Argv(1), "anglesz"))
4278 if (Cmd_Argc() != 3)
4280 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4283 angles[2] = atof(Cmd_Argv(2));
4285 else if (!strcmp(Cmd_Argv(1), "color"))
4287 if (Cmd_Argc() != 5)
4289 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
4292 color[0] = atof(Cmd_Argv(2));
4293 color[1] = atof(Cmd_Argv(3));
4294 color[2] = atof(Cmd_Argv(4));
4296 else if (!strcmp(Cmd_Argv(1), "radius"))
4298 if (Cmd_Argc() != 3)
4300 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4303 radius = atof(Cmd_Argv(2));
4305 else if (!strcmp(Cmd_Argv(1), "colorscale"))
4307 if (Cmd_Argc() == 3)
4309 double scale = atof(Cmd_Argv(2));
4316 if (Cmd_Argc() != 5)
4318 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
4321 color[0] *= atof(Cmd_Argv(2));
4322 color[1] *= atof(Cmd_Argv(3));
4323 color[2] *= atof(Cmd_Argv(4));
4326 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
4328 if (Cmd_Argc() != 3)
4330 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4333 radius *= atof(Cmd_Argv(2));
4335 else if (!strcmp(Cmd_Argv(1), "style"))
4337 if (Cmd_Argc() != 3)
4339 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4342 style = atoi(Cmd_Argv(2));
4344 else if (!strcmp(Cmd_Argv(1), "cubemap"))
4348 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4351 if (Cmd_Argc() == 3)
4352 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
4356 else if (!strcmp(Cmd_Argv(1), "shadows"))
4358 if (Cmd_Argc() != 3)
4360 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4363 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4365 else if (!strcmp(Cmd_Argv(1), "corona"))
4367 if (Cmd_Argc() != 3)
4369 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4372 corona = atof(Cmd_Argv(2));
4374 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4376 if (Cmd_Argc() != 3)
4378 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4381 coronasizescale = atof(Cmd_Argv(2));
4383 else if (!strcmp(Cmd_Argv(1), "ambient"))
4385 if (Cmd_Argc() != 3)
4387 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4390 ambientscale = atof(Cmd_Argv(2));
4392 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4394 if (Cmd_Argc() != 3)
4396 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4399 diffusescale = atof(Cmd_Argv(2));
4401 else if (!strcmp(Cmd_Argv(1), "specular"))
4403 if (Cmd_Argc() != 3)
4405 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4408 specularscale = atof(Cmd_Argv(2));
4410 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4412 if (Cmd_Argc() != 3)
4414 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4417 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4419 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4421 if (Cmd_Argc() != 3)
4423 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4426 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4430 Con_Print("usage: r_editlights_edit [property] [value]\n");
4431 Con_Print("Selected light's properties:\n");
4432 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4433 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4434 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4435 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4436 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4437 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4438 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4439 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4440 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4441 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4442 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4443 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4444 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4445 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4448 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4449 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4452 void R_Shadow_EditLights_EditAll_f(void)
4458 if (!r_editlights.integer)
4460 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4464 // EditLights doesn't seem to have a "remove" command or something so:
4465 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4466 for (lightindex = 0;lightindex < range;lightindex++)
4468 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4471 R_Shadow_SelectLight(light);
4472 R_Shadow_EditLights_Edit_f();
4476 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4478 int lightnumber, lightcount;
4479 size_t lightindex, range;
4483 if (!r_editlights.integer)
4485 x = vid_conwidth.value - 240;
4487 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
4490 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4491 for (lightindex = 0;lightindex < range;lightindex++)
4493 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4496 if (light == r_shadow_selectedlight)
4497 lightnumber = lightindex;
4500 dpsnprintf(temp, sizeof(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;
4501 dpsnprintf(temp, sizeof(temp), "Total lights : %i active (%i total)", lightcount, (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray)); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false);y += 8;
4503 if (r_shadow_selectedlight == NULL)
4505 dpsnprintf(temp, sizeof(temp), "Light #%i properties:", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4506 dpsnprintf(temp, sizeof(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;
4507 dpsnprintf(temp, sizeof(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;
4508 dpsnprintf(temp, sizeof(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;
4509 dpsnprintf(temp, sizeof(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;
4510 dpsnprintf(temp, sizeof(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;
4511 dpsnprintf(temp, sizeof(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;
4512 dpsnprintf(temp, sizeof(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;
4513 dpsnprintf(temp, sizeof(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;
4514 dpsnprintf(temp, sizeof(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;
4515 dpsnprintf(temp, sizeof(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;
4516 dpsnprintf(temp, sizeof(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;
4517 dpsnprintf(temp, sizeof(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;
4518 dpsnprintf(temp, sizeof(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;
4519 dpsnprintf(temp, sizeof(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;
4522 void R_Shadow_EditLights_ToggleShadow_f(void)
4524 if (!r_editlights.integer)
4526 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4529 if (!r_shadow_selectedlight)
4531 Con_Print("No selected light.\n");
4534 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);
4537 void R_Shadow_EditLights_ToggleCorona_f(void)
4539 if (!r_editlights.integer)
4541 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4544 if (!r_shadow_selectedlight)
4546 Con_Print("No selected light.\n");
4549 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);
4552 void R_Shadow_EditLights_Remove_f(void)
4554 if (!r_editlights.integer)
4556 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4559 if (!r_shadow_selectedlight)
4561 Con_Print("No selected light.\n");
4564 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4565 r_shadow_selectedlight = NULL;
4568 void R_Shadow_EditLights_Help_f(void)
4571 "Documentation on r_editlights system:\n"
4573 "r_editlights : enable/disable editing mode\n"
4574 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4575 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4576 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4577 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4578 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4580 "r_editlights_help : this help\n"
4581 "r_editlights_clear : remove all lights\n"
4582 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4583 "r_editlights_save : save to .rtlights file\n"
4584 "r_editlights_spawn : create a light with default settings\n"
4585 "r_editlights_edit command : edit selected light - more documentation below\n"
4586 "r_editlights_remove : remove selected light\n"
4587 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4588 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4589 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4591 "origin x y z : set light location\n"
4592 "originx x: set x component of light location\n"
4593 "originy y: set y component of light location\n"
4594 "originz z: set z component of light location\n"
4595 "move x y z : adjust light location\n"
4596 "movex x: adjust x component of light location\n"
4597 "movey y: adjust y component of light location\n"
4598 "movez z: adjust z component of light location\n"
4599 "angles x y z : set light angles\n"
4600 "anglesx x: set x component of light angles\n"
4601 "anglesy y: set y component of light angles\n"
4602 "anglesz z: set z component of light angles\n"
4603 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4604 "radius radius : set radius (size) of light\n"
4605 "colorscale grey : multiply color of light (1 does nothing)\n"
4606 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4607 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4608 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4609 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4610 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4611 "shadows 1/0 : turn on/off shadows\n"
4612 "corona n : set corona intensity\n"
4613 "coronasize n : set corona size (0-1)\n"
4614 "ambient n : set ambient intensity (0-1)\n"
4615 "diffuse n : set diffuse intensity (0-1)\n"
4616 "specular n : set specular intensity (0-1)\n"
4617 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4618 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4619 "<nothing> : print light properties to console\n"
4623 void R_Shadow_EditLights_CopyInfo_f(void)
4625 if (!r_editlights.integer)
4627 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4630 if (!r_shadow_selectedlight)
4632 Con_Print("No selected light.\n");
4635 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4636 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4637 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4638 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4639 if (r_shadow_selectedlight->cubemapname)
4640 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
4642 r_shadow_bufferlight.cubemapname[0] = 0;
4643 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4644 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4645 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4646 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4647 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4648 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4649 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4652 void R_Shadow_EditLights_PasteInfo_f(void)
4654 if (!r_editlights.integer)
4656 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4659 if (!r_shadow_selectedlight)
4661 Con_Print("No selected light.\n");
4664 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);
4667 void R_Shadow_EditLights_Init(void)
4669 Cvar_RegisterVariable(&r_editlights);
4670 Cvar_RegisterVariable(&r_editlights_cursordistance);
4671 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4672 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4673 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4674 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4675 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
4676 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
4677 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)");
4678 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
4679 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
4680 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
4681 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)");
4682 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
4683 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
4684 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
4685 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
4686 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
4687 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
4688 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)");
4694 =============================================================================
4698 =============================================================================
4701 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
4703 VectorClear(diffusecolor);
4704 VectorClear(diffusenormal);
4706 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
4708 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
4709 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
4712 VectorSet(ambientcolor, 1, 1, 1);
4719 for (i = 0;i < r_refdef.scene.numlights;i++)
4721 light = &r_refdef.scene.lights[i];
4722 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
4723 f = 1 - VectorLength2(v);
4724 if (f > 0 && CL_Move(p, vec3_origin, vec3_origin, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
4725 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);