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_glossexact = {0, "r_shadow_glossexact", "1", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
215 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
216 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
217 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
218 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
219 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
220 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
221 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)"};
222 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
223 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
224 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
225 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
226 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)"};
227 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"};
228 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
229 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
230 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"};
231 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
232 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
233 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)"};
234 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
235 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
236 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)"};
237 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)"};
238 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
239 cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksm the proportion of hidden pixels controls corona intensity"};
240 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
241 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
242 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
243 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
244 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
245 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
246 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
247 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
248 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
249 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
251 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
252 #define ATTENTABLESIZE 256
253 // 1D gradient, 2D circle and 3D sphere attenuation textures
254 #define ATTEN1DSIZE 32
255 #define ATTEN2DSIZE 64
256 #define ATTEN3DSIZE 32
258 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
259 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
260 static float r_shadow_attentable[ATTENTABLESIZE+1];
262 rtlight_t *r_shadow_compilingrtlight;
263 static memexpandablearray_t r_shadow_worldlightsarray;
264 dlight_t *r_shadow_selectedlight;
265 dlight_t r_shadow_bufferlight;
266 vec3_t r_editlights_cursorlocation;
268 extern int con_vislines;
270 typedef struct cubemapinfo_s
277 #define MAX_CUBEMAPS 256
278 static int numcubemaps;
279 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
281 void R_Shadow_UncompileWorldLights(void);
282 void R_Shadow_ClearWorldLights(void);
283 void R_Shadow_SaveWorldLights(void);
284 void R_Shadow_LoadWorldLights(void);
285 void R_Shadow_LoadLightsFile(void);
286 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
287 void R_Shadow_EditLights_Reload_f(void);
288 void R_Shadow_ValidateCvars(void);
289 static void R_Shadow_MakeTextures(void);
291 // VorteX: custom editor light sprites
292 #define EDLIGHTSPRSIZE 8
293 cachepic_t *r_editlights_sprcursor;
294 cachepic_t *r_editlights_sprlight;
295 cachepic_t *r_editlights_sprnoshadowlight;
296 cachepic_t *r_editlights_sprcubemaplight;
297 cachepic_t *r_editlights_sprcubemapnoshadowlight;
298 cachepic_t *r_editlights_sprselection;
300 void r_shadow_start(void)
302 // allocate vertex processing arrays
304 r_shadow_attenuationgradienttexture = NULL;
305 r_shadow_attenuation2dtexture = NULL;
306 r_shadow_attenuation3dtexture = NULL;
307 r_shadow_texturepool = NULL;
308 r_shadow_filters_texturepool = NULL;
309 R_Shadow_ValidateCvars();
310 R_Shadow_MakeTextures();
311 maxshadowtriangles = 0;
312 shadowelements = NULL;
313 maxshadowvertices = 0;
314 shadowvertex3f = NULL;
322 shadowmarklist = NULL;
324 r_shadow_buffer_numleafpvsbytes = 0;
325 r_shadow_buffer_visitingleafpvs = NULL;
326 r_shadow_buffer_leafpvs = NULL;
327 r_shadow_buffer_leaflist = NULL;
328 r_shadow_buffer_numsurfacepvsbytes = 0;
329 r_shadow_buffer_surfacepvs = NULL;
330 r_shadow_buffer_surfacelist = NULL;
331 r_shadow_buffer_numshadowtrispvsbytes = 0;
332 r_shadow_buffer_shadowtrispvs = NULL;
333 r_shadow_buffer_numlighttrispvsbytes = 0;
334 r_shadow_buffer_lighttrispvs = NULL;
337 void r_shadow_shutdown(void)
339 R_Shadow_UncompileWorldLights();
341 r_shadow_attenuationgradienttexture = NULL;
342 r_shadow_attenuation2dtexture = NULL;
343 r_shadow_attenuation3dtexture = NULL;
344 R_FreeTexturePool(&r_shadow_texturepool);
345 R_FreeTexturePool(&r_shadow_filters_texturepool);
346 maxshadowtriangles = 0;
348 Mem_Free(shadowelements);
349 shadowelements = NULL;
351 Mem_Free(shadowvertex3f);
352 shadowvertex3f = NULL;
355 Mem_Free(vertexupdate);
358 Mem_Free(vertexremap);
364 Mem_Free(shadowmark);
367 Mem_Free(shadowmarklist);
368 shadowmarklist = NULL;
370 r_shadow_buffer_numleafpvsbytes = 0;
371 if (r_shadow_buffer_visitingleafpvs)
372 Mem_Free(r_shadow_buffer_visitingleafpvs);
373 r_shadow_buffer_visitingleafpvs = NULL;
374 if (r_shadow_buffer_leafpvs)
375 Mem_Free(r_shadow_buffer_leafpvs);
376 r_shadow_buffer_leafpvs = NULL;
377 if (r_shadow_buffer_leaflist)
378 Mem_Free(r_shadow_buffer_leaflist);
379 r_shadow_buffer_leaflist = NULL;
380 r_shadow_buffer_numsurfacepvsbytes = 0;
381 if (r_shadow_buffer_surfacepvs)
382 Mem_Free(r_shadow_buffer_surfacepvs);
383 r_shadow_buffer_surfacepvs = NULL;
384 if (r_shadow_buffer_surfacelist)
385 Mem_Free(r_shadow_buffer_surfacelist);
386 r_shadow_buffer_surfacelist = NULL;
387 r_shadow_buffer_numshadowtrispvsbytes = 0;
388 if (r_shadow_buffer_shadowtrispvs)
389 Mem_Free(r_shadow_buffer_shadowtrispvs);
390 r_shadow_buffer_numlighttrispvsbytes = 0;
391 if (r_shadow_buffer_lighttrispvs)
392 Mem_Free(r_shadow_buffer_lighttrispvs);
395 void r_shadow_newmap(void)
397 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
398 R_Shadow_EditLights_Reload_f();
401 void R_Shadow_Help_f(void)
404 "Documentation on r_shadow system:\n"
406 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
407 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
408 "r_shadow_debuglight : render only this light number (-1 = all)\n"
409 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
410 "r_shadow_gloss2intensity : brightness of forced gloss\n"
411 "r_shadow_glossintensity : brightness of textured gloss\n"
412 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
413 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
414 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
415 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
416 "r_shadow_portallight : use portal visibility for static light precomputation\n"
417 "r_shadow_projectdistance : shadow volume projection distance\n"
418 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
419 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
420 "r_shadow_realtime_world : use high quality world lighting mode\n"
421 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
422 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
423 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
424 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
425 "r_shadow_scissor : use scissor optimization\n"
426 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
427 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
428 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
429 "r_showlighting : useful for performance testing; bright = slow!\n"
430 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
432 "r_shadow_help : this help\n"
436 void R_Shadow_Init(void)
438 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
439 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
440 Cvar_RegisterVariable(&r_shadow_usenormalmap);
441 Cvar_RegisterVariable(&r_shadow_debuglight);
442 Cvar_RegisterVariable(&r_shadow_gloss);
443 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
444 Cvar_RegisterVariable(&r_shadow_glossintensity);
445 Cvar_RegisterVariable(&r_shadow_glossexponent);
446 Cvar_RegisterVariable(&r_shadow_glossexact);
447 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
448 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
449 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
450 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
451 Cvar_RegisterVariable(&r_shadow_portallight);
452 Cvar_RegisterVariable(&r_shadow_projectdistance);
453 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
454 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
455 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
456 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
457 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
458 Cvar_RegisterVariable(&r_shadow_realtime_world);
459 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
460 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
461 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
462 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
463 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
464 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
465 Cvar_RegisterVariable(&r_shadow_scissor);
466 Cvar_RegisterVariable(&r_shadow_culltriangles);
467 Cvar_RegisterVariable(&r_shadow_polygonfactor);
468 Cvar_RegisterVariable(&r_shadow_polygonoffset);
469 Cvar_RegisterVariable(&r_shadow_texture3d);
470 Cvar_RegisterVariable(&r_coronas);
471 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
472 Cvar_RegisterVariable(&r_coronas_occlusionquery);
473 Cvar_RegisterVariable(&gl_flashblend);
474 Cvar_RegisterVariable(&gl_ext_separatestencil);
475 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
476 if (gamemode == GAME_TENEBRAE)
478 Cvar_SetValue("r_shadow_gloss", 2);
479 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
481 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
482 R_Shadow_EditLights_Init();
483 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
484 maxshadowtriangles = 0;
485 shadowelements = NULL;
486 maxshadowvertices = 0;
487 shadowvertex3f = NULL;
495 shadowmarklist = NULL;
497 r_shadow_buffer_numleafpvsbytes = 0;
498 r_shadow_buffer_visitingleafpvs = NULL;
499 r_shadow_buffer_leafpvs = NULL;
500 r_shadow_buffer_leaflist = NULL;
501 r_shadow_buffer_numsurfacepvsbytes = 0;
502 r_shadow_buffer_surfacepvs = NULL;
503 r_shadow_buffer_surfacelist = NULL;
504 r_shadow_buffer_shadowtrispvs = NULL;
505 r_shadow_buffer_lighttrispvs = NULL;
506 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
509 matrix4x4_t matrix_attenuationxyz =
512 {0.5, 0.0, 0.0, 0.5},
513 {0.0, 0.5, 0.0, 0.5},
514 {0.0, 0.0, 0.5, 0.5},
519 matrix4x4_t matrix_attenuationz =
522 {0.0, 0.0, 0.5, 0.5},
523 {0.0, 0.0, 0.0, 0.5},
524 {0.0, 0.0, 0.0, 0.5},
529 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
531 // make sure shadowelements is big enough for this volume
532 if (maxshadowtriangles < numtriangles)
534 maxshadowtriangles = numtriangles;
536 Mem_Free(shadowelements);
537 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
539 // make sure shadowvertex3f is big enough for this volume
540 if (maxshadowvertices < numvertices)
542 maxshadowvertices = numvertices;
544 Mem_Free(shadowvertex3f);
545 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
549 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
551 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
552 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
553 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
554 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
555 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
557 if (r_shadow_buffer_visitingleafpvs)
558 Mem_Free(r_shadow_buffer_visitingleafpvs);
559 if (r_shadow_buffer_leafpvs)
560 Mem_Free(r_shadow_buffer_leafpvs);
561 if (r_shadow_buffer_leaflist)
562 Mem_Free(r_shadow_buffer_leaflist);
563 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
564 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
565 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
566 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
568 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
570 if (r_shadow_buffer_surfacepvs)
571 Mem_Free(r_shadow_buffer_surfacepvs);
572 if (r_shadow_buffer_surfacelist)
573 Mem_Free(r_shadow_buffer_surfacelist);
574 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
575 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
576 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
578 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
580 if (r_shadow_buffer_shadowtrispvs)
581 Mem_Free(r_shadow_buffer_shadowtrispvs);
582 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
583 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
585 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
587 if (r_shadow_buffer_lighttrispvs)
588 Mem_Free(r_shadow_buffer_lighttrispvs);
589 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
590 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
594 void R_Shadow_PrepareShadowMark(int numtris)
596 // make sure shadowmark is big enough for this volume
597 if (maxshadowmark < numtris)
599 maxshadowmark = numtris;
601 Mem_Free(shadowmark);
603 Mem_Free(shadowmarklist);
604 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
605 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
609 // if shadowmarkcount wrapped we clear the array and adjust accordingly
610 if (shadowmarkcount == 0)
613 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
618 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)
621 int outtriangles = 0, outvertices = 0;
624 float ratio, direction[3], projectvector[3];
626 if (projectdirection)
627 VectorScale(projectdirection, projectdistance, projectvector);
629 VectorClear(projectvector);
631 // create the vertices
632 if (projectdirection)
634 for (i = 0;i < numshadowmarktris;i++)
636 element = inelement3i + shadowmarktris[i] * 3;
637 for (j = 0;j < 3;j++)
639 if (vertexupdate[element[j]] != vertexupdatenum)
641 vertexupdate[element[j]] = vertexupdatenum;
642 vertexremap[element[j]] = outvertices;
643 vertex = invertex3f + element[j] * 3;
644 // project one copy of the vertex according to projectvector
645 VectorCopy(vertex, outvertex3f);
646 VectorAdd(vertex, projectvector, (outvertex3f + 3));
655 for (i = 0;i < numshadowmarktris;i++)
657 element = inelement3i + shadowmarktris[i] * 3;
658 for (j = 0;j < 3;j++)
660 if (vertexupdate[element[j]] != vertexupdatenum)
662 vertexupdate[element[j]] = vertexupdatenum;
663 vertexremap[element[j]] = outvertices;
664 vertex = invertex3f + element[j] * 3;
665 // project one copy of the vertex to the sphere radius of the light
666 // (FIXME: would projecting it to the light box be better?)
667 VectorSubtract(vertex, projectorigin, direction);
668 ratio = projectdistance / VectorLength(direction);
669 VectorCopy(vertex, outvertex3f);
670 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
678 if (r_shadow_frontsidecasting.integer)
680 for (i = 0;i < numshadowmarktris;i++)
682 int remappedelement[3];
684 const int *neighbortriangle;
686 markindex = shadowmarktris[i] * 3;
687 element = inelement3i + markindex;
688 neighbortriangle = inneighbor3i + markindex;
689 // output the front and back triangles
690 outelement3i[0] = vertexremap[element[0]];
691 outelement3i[1] = vertexremap[element[1]];
692 outelement3i[2] = vertexremap[element[2]];
693 outelement3i[3] = vertexremap[element[2]] + 1;
694 outelement3i[4] = vertexremap[element[1]] + 1;
695 outelement3i[5] = vertexremap[element[0]] + 1;
699 // output the sides (facing outward from this triangle)
700 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
702 remappedelement[0] = vertexremap[element[0]];
703 remappedelement[1] = vertexremap[element[1]];
704 outelement3i[0] = remappedelement[1];
705 outelement3i[1] = remappedelement[0];
706 outelement3i[2] = remappedelement[0] + 1;
707 outelement3i[3] = remappedelement[1];
708 outelement3i[4] = remappedelement[0] + 1;
709 outelement3i[5] = remappedelement[1] + 1;
714 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
716 remappedelement[1] = vertexremap[element[1]];
717 remappedelement[2] = vertexremap[element[2]];
718 outelement3i[0] = remappedelement[2];
719 outelement3i[1] = remappedelement[1];
720 outelement3i[2] = remappedelement[1] + 1;
721 outelement3i[3] = remappedelement[2];
722 outelement3i[4] = remappedelement[1] + 1;
723 outelement3i[5] = remappedelement[2] + 1;
728 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
730 remappedelement[0] = vertexremap[element[0]];
731 remappedelement[2] = vertexremap[element[2]];
732 outelement3i[0] = remappedelement[0];
733 outelement3i[1] = remappedelement[2];
734 outelement3i[2] = remappedelement[2] + 1;
735 outelement3i[3] = remappedelement[0];
736 outelement3i[4] = remappedelement[2] + 1;
737 outelement3i[5] = remappedelement[0] + 1;
746 for (i = 0;i < numshadowmarktris;i++)
748 int remappedelement[3];
750 const int *neighbortriangle;
752 markindex = shadowmarktris[i] * 3;
753 element = inelement3i + markindex;
754 neighbortriangle = inneighbor3i + markindex;
755 // output the front and back triangles
756 outelement3i[0] = vertexremap[element[2]];
757 outelement3i[1] = vertexremap[element[1]];
758 outelement3i[2] = vertexremap[element[0]];
759 outelement3i[3] = vertexremap[element[0]] + 1;
760 outelement3i[4] = vertexremap[element[1]] + 1;
761 outelement3i[5] = vertexremap[element[2]] + 1;
765 // output the sides (facing outward from this triangle)
766 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
768 remappedelement[0] = vertexremap[element[0]];
769 remappedelement[1] = vertexremap[element[1]];
770 outelement3i[0] = remappedelement[0];
771 outelement3i[1] = remappedelement[1];
772 outelement3i[2] = remappedelement[1] + 1;
773 outelement3i[3] = remappedelement[0];
774 outelement3i[4] = remappedelement[1] + 1;
775 outelement3i[5] = remappedelement[0] + 1;
780 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
782 remappedelement[1] = vertexremap[element[1]];
783 remappedelement[2] = vertexremap[element[2]];
784 outelement3i[0] = remappedelement[1];
785 outelement3i[1] = remappedelement[2];
786 outelement3i[2] = remappedelement[2] + 1;
787 outelement3i[3] = remappedelement[1];
788 outelement3i[4] = remappedelement[2] + 1;
789 outelement3i[5] = remappedelement[1] + 1;
794 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
796 remappedelement[0] = vertexremap[element[0]];
797 remappedelement[2] = vertexremap[element[2]];
798 outelement3i[0] = remappedelement[2];
799 outelement3i[1] = remappedelement[0];
800 outelement3i[2] = remappedelement[0] + 1;
801 outelement3i[3] = remappedelement[2];
802 outelement3i[4] = remappedelement[0] + 1;
803 outelement3i[5] = remappedelement[2] + 1;
811 *outnumvertices = outvertices;
815 void R_Shadow_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)
821 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
823 tend = firsttriangle + numtris;
824 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
826 // surface box entirely inside light box, no box cull
827 if (projectdirection)
829 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
831 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
832 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
833 shadowmarklist[numshadowmark++] = t;
838 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
839 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
840 shadowmarklist[numshadowmark++] = t;
845 // surface box not entirely inside light box, cull each triangle
846 if (projectdirection)
848 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
850 v[0] = invertex3f + e[0] * 3;
851 v[1] = invertex3f + e[1] * 3;
852 v[2] = invertex3f + e[2] * 3;
853 TriangleNormal(v[0], v[1], v[2], normal);
854 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
855 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
856 shadowmarklist[numshadowmark++] = t;
861 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
863 v[0] = invertex3f + e[0] * 3;
864 v[1] = invertex3f + e[1] * 3;
865 v[2] = invertex3f + e[2] * 3;
866 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
867 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
868 shadowmarklist[numshadowmark++] = t;
874 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, vec3_t trismins, vec3_t trismaxs)
876 int i, tris, outverts;
877 if (projectdistance < 0.1)
879 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
882 if (!numverts || !nummarktris)
884 // make sure shadowelements is big enough for this volume
885 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
886 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
888 if (maxvertexupdate < numverts)
890 maxvertexupdate = numverts;
892 Mem_Free(vertexupdate);
894 Mem_Free(vertexremap);
895 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
896 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
900 if (vertexupdatenum == 0)
903 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
904 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
907 for (i = 0;i < nummarktris;i++)
908 shadowmark[marktris[i]] = shadowmarkcount;
910 if (r_shadow_compilingrtlight)
912 // if we're compiling an rtlight, capture the mesh
913 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
914 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
918 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
919 r_refdef.stats.lights_dynamicshadowtriangles += tris;
920 r_refdef.stats.lights_shadowtriangles += tris;
922 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
923 GL_LockArrays(0, outverts);
924 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
926 // decrement stencil if backface is behind depthbuffer
927 GL_CullFace(r_refdef.view.cullface_front);
928 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
929 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
930 // increment stencil if frontface is behind depthbuffer
931 GL_CullFace(r_refdef.view.cullface_back);
932 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
934 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
940 static void R_Shadow_MakeTextures_MakeCorona(void)
944 unsigned char pixels[32][32][4];
945 for (y = 0;y < 32;y++)
947 dy = (y - 15.5f) * (1.0f / 16.0f);
948 for (x = 0;x < 32;x++)
950 dx = (x - 15.5f) * (1.0f / 16.0f);
951 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
952 a = bound(0, a, 255);
956 pixels[y][x][3] = 255;
959 r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE, NULL);
962 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
964 float dist = sqrt(x*x+y*y+z*z);
965 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
966 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
967 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
970 static void R_Shadow_MakeTextures(void)
973 float intensity, dist;
975 R_FreeTexturePool(&r_shadow_texturepool);
976 r_shadow_texturepool = R_AllocTexturePool();
977 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
978 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
979 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
980 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
981 for (x = 0;x <= ATTENTABLESIZE;x++)
983 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
984 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
985 r_shadow_attentable[x] = bound(0, intensity, 1);
987 // 1D gradient texture
988 for (x = 0;x < ATTEN1DSIZE;x++)
989 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
990 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
992 for (y = 0;y < ATTEN2DSIZE;y++)
993 for (x = 0;x < ATTEN2DSIZE;x++)
994 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);
995 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
997 if (r_shadow_texture3d.integer && gl_texture3d)
999 for (z = 0;z < ATTEN3DSIZE;z++)
1000 for (y = 0;y < ATTEN3DSIZE;y++)
1001 for (x = 0;x < ATTEN3DSIZE;x++)
1002 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));
1003 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
1006 r_shadow_attenuation3dtexture = NULL;
1009 R_Shadow_MakeTextures_MakeCorona();
1011 // Editor light sprites
1012 r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
1013 r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
1014 r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
1015 r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
1016 r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
1017 r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
1020 void R_Shadow_ValidateCvars(void)
1022 if (r_shadow_texture3d.integer && !gl_texture3d)
1023 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1024 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1025 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1026 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1027 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1030 void R_Shadow_RenderMode_Begin(void)
1032 R_Shadow_ValidateCvars();
1034 if (!r_shadow_attenuation2dtexture
1035 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1036 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1037 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1038 R_Shadow_MakeTextures();
1041 R_Mesh_ColorPointer(NULL, 0, 0);
1042 R_Mesh_ResetTextureState();
1043 GL_BlendFunc(GL_ONE, GL_ZERO);
1044 GL_DepthRange(0, 1);
1045 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1047 GL_DepthMask(false);
1048 GL_Color(0, 0, 0, 1);
1049 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
1051 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1053 if (gl_ext_separatestencil.integer)
1054 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
1055 else if (gl_ext_stenciltwoside.integer)
1056 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
1058 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
1060 if (r_glsl.integer && gl_support_fragment_shader)
1061 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1062 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1063 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1065 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1068 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1070 rsurface.rtlight = rtlight;
1073 void R_Shadow_RenderMode_Reset(void)
1076 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1078 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1080 R_Mesh_ColorPointer(NULL, 0, 0);
1081 R_Mesh_ResetTextureState();
1082 GL_DepthRange(0, 1);
1084 GL_DepthMask(false);
1085 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1086 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1087 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1088 qglStencilMask(~0);CHECKGLERROR
1089 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1090 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1091 GL_CullFace(r_refdef.view.cullface_back);
1092 GL_Color(1, 1, 1, 1);
1093 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1094 GL_BlendFunc(GL_ONE, GL_ZERO);
1095 R_SetupGenericShader(false);
1098 void R_Shadow_ClearStencil(void)
1101 GL_Clear(GL_STENCIL_BUFFER_BIT);
1102 r_refdef.stats.lights_clears++;
1105 void R_Shadow_RenderMode_StencilShadowVolumes(void)
1108 R_Shadow_RenderMode_Reset();
1109 GL_ColorMask(0, 0, 0, 0);
1110 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1111 R_SetupDepthOrShadowShader();
1112 qglDepthFunc(GL_LESS);CHECKGLERROR
1113 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1114 r_shadow_rendermode = r_shadow_shadowingrendermode;
1115 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SEPARATESTENCIL)
1117 GL_CullFace(GL_NONE);
1118 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1119 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1121 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1123 GL_CullFace(GL_NONE);
1124 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1125 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1126 qglStencilMask(~0);CHECKGLERROR
1127 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1128 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1129 qglStencilMask(~0);CHECKGLERROR
1130 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1134 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
1137 R_Shadow_RenderMode_Reset();
1138 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1141 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1145 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1146 // only draw light where this geometry was already rendered AND the
1147 // stencil is 128 (values other than this mean shadow)
1148 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1150 r_shadow_rendermode = r_shadow_lightingrendermode;
1151 // do global setup needed for the chosen lighting mode
1152 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1154 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
1155 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1157 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
1158 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
1159 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1162 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1165 R_Shadow_RenderMode_Reset();
1166 GL_BlendFunc(GL_ONE, GL_ONE);
1167 GL_DepthRange(0, 1);
1168 GL_DepthTest(r_showshadowvolumes.integer < 2);
1169 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
1170 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1171 GL_CullFace(GL_NONE);
1172 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1175 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1178 R_Shadow_RenderMode_Reset();
1179 GL_BlendFunc(GL_ONE, GL_ONE);
1180 GL_DepthRange(0, 1);
1181 GL_DepthTest(r_showlighting.integer < 2);
1182 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
1185 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1189 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1190 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1192 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1195 void R_Shadow_RenderMode_End(void)
1198 R_Shadow_RenderMode_Reset();
1199 R_Shadow_RenderMode_ActiveLight(NULL);
1201 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
1202 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1205 int bboxedges[12][2] =
1224 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1226 int i, ix1, iy1, ix2, iy2;
1227 float x1, y1, x2, y2;
1229 float vertex[20][3];
1238 if (!r_shadow_scissor.integer)
1241 // if view is inside the light box, just say yes it's visible
1242 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
1244 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
1248 x1 = y1 = x2 = y2 = 0;
1250 // transform all corners that are infront of the nearclip plane
1251 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
1252 plane4f[3] = r_refdef.view.frustum[4].dist;
1254 for (i = 0;i < 8;i++)
1256 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
1257 dist[i] = DotProduct4(corner[i], plane4f);
1258 sign[i] = dist[i] > 0;
1261 VectorCopy(corner[i], vertex[numvertices]);
1265 // if some points are behind the nearclip, add clipped edge points to make
1266 // sure that the scissor boundary is complete
1267 if (numvertices > 0 && numvertices < 8)
1269 // add clipped edge points
1270 for (i = 0;i < 12;i++)
1272 j = bboxedges[i][0];
1273 k = bboxedges[i][1];
1274 if (sign[j] != sign[k])
1276 f = dist[j] / (dist[j] - dist[k]);
1277 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
1283 // if we have no points to check, the light is behind the view plane
1287 // if we have some points to transform, check what screen area is covered
1288 x1 = y1 = x2 = y2 = 0;
1290 //Con_Printf("%i vertices to transform...\n", numvertices);
1291 for (i = 0;i < numvertices;i++)
1293 VectorCopy(vertex[i], v);
1294 GL_TransformToScreen(v, v2);
1295 //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]);
1298 if (x1 > v2[0]) x1 = v2[0];
1299 if (x2 < v2[0]) x2 = v2[0];
1300 if (y1 > v2[1]) y1 = v2[1];
1301 if (y2 < v2[1]) y2 = v2[1];
1310 // now convert the scissor rectangle to integer screen coordinates
1311 ix1 = (int)(x1 - 1.0f);
1312 iy1 = (int)(y1 - 1.0f);
1313 ix2 = (int)(x2 + 1.0f);
1314 iy2 = (int)(y2 + 1.0f);
1315 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1317 // clamp it to the screen
1318 if (ix1 < r_refdef.view.x) ix1 = r_refdef.view.x;
1319 if (iy1 < r_refdef.view.y) iy1 = r_refdef.view.y;
1320 if (ix2 > r_refdef.view.x + r_refdef.view.width) ix2 = r_refdef.view.x + r_refdef.view.width;
1321 if (iy2 > r_refdef.view.y + r_refdef.view.height) iy2 = r_refdef.view.y + r_refdef.view.height;
1323 // if it is inside out, it's not visible
1324 if (ix2 <= ix1 || iy2 <= iy1)
1327 // the light area is visible, set up the scissor rectangle
1328 GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1329 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1330 //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1331 r_refdef.stats.lights_scissored++;
1335 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1337 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1338 float *normal3f = rsurface.normal3f + 3 * firstvertex;
1339 float *color4f = rsurface.array_color4f + 4 * firstvertex;
1340 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1341 if (r_textureunits.integer >= 3)
1343 if (VectorLength2(diffusecolor) > 0)
1345 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1347 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1348 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1349 if ((dot = DotProduct(n, v)) < 0)
1351 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1352 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1355 VectorCopy(ambientcolor, color4f);
1356 if (r_refdef.fogenabled)
1359 f = FogPoint_Model(vertex3f);
1360 VectorScale(color4f, f, color4f);
1367 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1369 VectorCopy(ambientcolor, color4f);
1370 if (r_refdef.fogenabled)
1373 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1374 f = FogPoint_Model(vertex3f);
1375 VectorScale(color4f, f, color4f);
1381 else if (r_textureunits.integer >= 2)
1383 if (VectorLength2(diffusecolor) > 0)
1385 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1387 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1388 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1390 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1391 if ((dot = DotProduct(n, v)) < 0)
1393 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1394 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1395 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1396 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1400 color4f[0] = ambientcolor[0] * distintensity;
1401 color4f[1] = ambientcolor[1] * distintensity;
1402 color4f[2] = ambientcolor[2] * distintensity;
1404 if (r_refdef.fogenabled)
1407 f = FogPoint_Model(vertex3f);
1408 VectorScale(color4f, f, color4f);
1412 VectorClear(color4f);
1418 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1420 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1421 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1423 color4f[0] = ambientcolor[0] * distintensity;
1424 color4f[1] = ambientcolor[1] * distintensity;
1425 color4f[2] = ambientcolor[2] * distintensity;
1426 if (r_refdef.fogenabled)
1429 f = FogPoint_Model(vertex3f);
1430 VectorScale(color4f, f, color4f);
1434 VectorClear(color4f);
1441 if (VectorLength2(diffusecolor) > 0)
1443 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1445 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1446 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1448 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1449 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1450 if ((dot = DotProduct(n, v)) < 0)
1452 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1453 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1454 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1455 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1459 color4f[0] = ambientcolor[0] * distintensity;
1460 color4f[1] = ambientcolor[1] * distintensity;
1461 color4f[2] = ambientcolor[2] * distintensity;
1463 if (r_refdef.fogenabled)
1466 f = FogPoint_Model(vertex3f);
1467 VectorScale(color4f, f, color4f);
1471 VectorClear(color4f);
1477 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1479 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1480 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1482 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1483 color4f[0] = ambientcolor[0] * distintensity;
1484 color4f[1] = ambientcolor[1] * distintensity;
1485 color4f[2] = ambientcolor[2] * distintensity;
1486 if (r_refdef.fogenabled)
1489 f = FogPoint_Model(vertex3f);
1490 VectorScale(color4f, f, color4f);
1494 VectorClear(color4f);
1501 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1503 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1506 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1507 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1508 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1509 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1510 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1512 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1514 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1515 // the cubemap normalizes this for us
1516 out3f[0] = DotProduct(svector3f, lightdir);
1517 out3f[1] = DotProduct(tvector3f, lightdir);
1518 out3f[2] = DotProduct(normal3f, lightdir);
1522 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1525 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1526 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1527 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1528 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1529 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1530 float lightdir[3], eyedir[3], halfdir[3];
1531 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1533 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1534 VectorNormalize(lightdir);
1535 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
1536 VectorNormalize(eyedir);
1537 VectorAdd(lightdir, eyedir, halfdir);
1538 // the cubemap normalizes this for us
1539 out3f[0] = DotProduct(svector3f, halfdir);
1540 out3f[1] = DotProduct(tvector3f, halfdir);
1541 out3f[2] = DotProduct(normal3f, halfdir);
1545 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)
1547 // used to display how many times a surface is lit for level design purposes
1548 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1551 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)
1553 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1554 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
1555 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
1556 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
1558 R_Mesh_ColorPointer(NULL, 0, 0);
1559 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
1560 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
1561 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
1562 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
1563 if (rsurface.texture->backgroundcurrentskinframe)
1565 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
1566 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
1567 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
1569 //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
1570 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
1571 if(rsurface.texture->colormapping)
1573 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
1574 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
1576 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
1577 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
1578 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
1579 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
1580 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
1581 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1583 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1585 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1586 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1588 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1592 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)
1594 // shared final code for all the dot3 layers
1596 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1597 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1599 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1600 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1604 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)
1607 // colorscale accounts for how much we multiply the brightness
1610 // mult is how many times the final pass of the lighting will be
1611 // performed to get more brightness than otherwise possible.
1613 // Limit mult to 64 for sanity sake.
1615 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1617 // 3 3D combine path (Geforce3, Radeon 8500)
1618 memset(&m, 0, sizeof(m));
1619 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1620 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1621 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1622 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1623 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1624 m.tex[1] = R_GetTexture(basetexture);
1625 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1626 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1627 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1628 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1629 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
1630 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1631 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1632 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1633 m.texmatrix[2] = rsurface.entitytolight;
1634 GL_BlendFunc(GL_ONE, GL_ONE);
1636 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1638 // 2 3D combine path (Geforce3, original Radeon)
1639 memset(&m, 0, sizeof(m));
1640 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1641 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1642 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1643 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1644 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1645 m.tex[1] = R_GetTexture(basetexture);
1646 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1647 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1648 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1649 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1650 GL_BlendFunc(GL_ONE, GL_ONE);
1652 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1654 // 4 2D combine path (Geforce3, Radeon 8500)
1655 memset(&m, 0, sizeof(m));
1656 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1657 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1658 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1659 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1660 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1661 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1662 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1663 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1664 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1665 m.texmatrix[1] = rsurface.entitytoattenuationz;
1666 m.tex[2] = R_GetTexture(basetexture);
1667 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1668 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1669 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1670 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1671 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1673 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
1674 m.pointer_texcoord3f[3] = rsurface.vertex3f;
1675 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
1676 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
1677 m.texmatrix[3] = rsurface.entitytolight;
1679 GL_BlendFunc(GL_ONE, GL_ONE);
1681 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1683 // 3 2D combine path (Geforce3, original Radeon)
1684 memset(&m, 0, sizeof(m));
1685 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1686 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1687 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1688 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1689 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1690 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1691 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1692 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1693 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1694 m.texmatrix[1] = rsurface.entitytoattenuationz;
1695 m.tex[2] = R_GetTexture(basetexture);
1696 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1697 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1698 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1699 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1700 GL_BlendFunc(GL_ONE, GL_ONE);
1704 // 2/2/2 2D combine path (any dot3 card)
1705 memset(&m, 0, sizeof(m));
1706 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1707 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1708 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1709 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1710 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1711 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1712 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1713 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1714 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1715 m.texmatrix[1] = rsurface.entitytoattenuationz;
1716 R_Mesh_TextureState(&m);
1717 GL_ColorMask(0,0,0,1);
1718 GL_BlendFunc(GL_ONE, GL_ZERO);
1719 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1722 memset(&m, 0, sizeof(m));
1723 m.tex[0] = R_GetTexture(basetexture);
1724 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1725 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1726 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1727 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1728 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1730 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1731 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1732 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1733 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1734 m.texmatrix[1] = rsurface.entitytolight;
1736 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1738 // this final code is shared
1739 R_Mesh_TextureState(&m);
1740 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);
1743 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)
1746 // colorscale accounts for how much we multiply the brightness
1749 // mult is how many times the final pass of the lighting will be
1750 // performed to get more brightness than otherwise possible.
1752 // Limit mult to 64 for sanity sake.
1754 // generate normalization cubemap texcoords
1755 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1756 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1758 // 3/2 3D combine path (Geforce3, Radeon 8500)
1759 memset(&m, 0, sizeof(m));
1760 m.tex[0] = R_GetTexture(normalmaptexture);
1761 m.texcombinergb[0] = GL_REPLACE;
1762 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1763 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1764 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1765 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1766 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1767 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1768 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1769 m.pointer_texcoord_bufferobject[1] = 0;
1770 m.pointer_texcoord_bufferoffset[1] = 0;
1771 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1772 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1773 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1774 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1775 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
1776 R_Mesh_TextureState(&m);
1777 GL_ColorMask(0,0,0,1);
1778 GL_BlendFunc(GL_ONE, GL_ZERO);
1779 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1782 memset(&m, 0, sizeof(m));
1783 m.tex[0] = R_GetTexture(basetexture);
1784 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1785 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1786 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1787 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1788 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1790 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1791 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1792 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1793 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1794 m.texmatrix[1] = rsurface.entitytolight;
1796 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1798 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1800 // 1/2/2 3D combine path (original Radeon)
1801 memset(&m, 0, sizeof(m));
1802 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1803 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1804 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1805 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1806 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1807 R_Mesh_TextureState(&m);
1808 GL_ColorMask(0,0,0,1);
1809 GL_BlendFunc(GL_ONE, GL_ZERO);
1810 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1813 memset(&m, 0, sizeof(m));
1814 m.tex[0] = R_GetTexture(normalmaptexture);
1815 m.texcombinergb[0] = GL_REPLACE;
1816 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1817 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1818 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1819 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1820 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1821 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1822 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1823 m.pointer_texcoord_bufferobject[1] = 0;
1824 m.pointer_texcoord_bufferoffset[1] = 0;
1825 R_Mesh_TextureState(&m);
1826 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1827 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1830 memset(&m, 0, sizeof(m));
1831 m.tex[0] = R_GetTexture(basetexture);
1832 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1833 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1834 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1835 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1836 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1838 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1839 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1840 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1841 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1842 m.texmatrix[1] = rsurface.entitytolight;
1844 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1846 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1848 // 2/2 3D combine path (original Radeon)
1849 memset(&m, 0, sizeof(m));
1850 m.tex[0] = R_GetTexture(normalmaptexture);
1851 m.texcombinergb[0] = GL_REPLACE;
1852 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1853 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1854 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1855 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1856 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1857 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1858 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1859 m.pointer_texcoord_bufferobject[1] = 0;
1860 m.pointer_texcoord_bufferoffset[1] = 0;
1861 R_Mesh_TextureState(&m);
1862 GL_ColorMask(0,0,0,1);
1863 GL_BlendFunc(GL_ONE, GL_ZERO);
1864 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1867 memset(&m, 0, sizeof(m));
1868 m.tex[0] = R_GetTexture(basetexture);
1869 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1870 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1871 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1872 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1873 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1874 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1875 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1876 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1877 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
1878 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1880 else if (r_textureunits.integer >= 4)
1882 // 4/2 2D combine path (Geforce3, Radeon 8500)
1883 memset(&m, 0, sizeof(m));
1884 m.tex[0] = R_GetTexture(normalmaptexture);
1885 m.texcombinergb[0] = GL_REPLACE;
1886 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1887 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1888 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1889 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1890 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1891 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1892 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1893 m.pointer_texcoord_bufferobject[1] = 0;
1894 m.pointer_texcoord_bufferoffset[1] = 0;
1895 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1896 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1897 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1898 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1899 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
1900 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1901 m.pointer_texcoord3f[3] = rsurface.vertex3f;
1902 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
1903 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
1904 m.texmatrix[3] = rsurface.entitytoattenuationz;
1905 R_Mesh_TextureState(&m);
1906 GL_ColorMask(0,0,0,1);
1907 GL_BlendFunc(GL_ONE, GL_ZERO);
1908 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1911 memset(&m, 0, sizeof(m));
1912 m.tex[0] = R_GetTexture(basetexture);
1913 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1914 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1915 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1916 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1917 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1919 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1920 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1921 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1922 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1923 m.texmatrix[1] = rsurface.entitytolight;
1925 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1929 // 2/2/2 2D combine path (any dot3 card)
1930 memset(&m, 0, sizeof(m));
1931 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1932 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1933 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1934 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1935 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1936 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1937 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1938 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1939 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1940 m.texmatrix[1] = rsurface.entitytoattenuationz;
1941 R_Mesh_TextureState(&m);
1942 GL_ColorMask(0,0,0,1);
1943 GL_BlendFunc(GL_ONE, GL_ZERO);
1944 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1947 memset(&m, 0, sizeof(m));
1948 m.tex[0] = R_GetTexture(normalmaptexture);
1949 m.texcombinergb[0] = GL_REPLACE;
1950 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1951 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1952 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1953 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1954 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1955 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1956 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1957 m.pointer_texcoord_bufferobject[1] = 0;
1958 m.pointer_texcoord_bufferoffset[1] = 0;
1959 R_Mesh_TextureState(&m);
1960 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1961 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1964 memset(&m, 0, sizeof(m));
1965 m.tex[0] = R_GetTexture(basetexture);
1966 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1967 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1968 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1969 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1970 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1972 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1973 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1974 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1975 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1976 m.texmatrix[1] = rsurface.entitytolight;
1978 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1980 // this final code is shared
1981 R_Mesh_TextureState(&m);
1982 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);
1985 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)
1987 float glossexponent;
1989 // FIXME: detect blendsquare!
1990 //if (!gl_support_blendsquare)
1993 // generate normalization cubemap texcoords
1994 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1995 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1997 // 2/0/0/1/2 3D combine blendsquare path
1998 memset(&m, 0, sizeof(m));
1999 m.tex[0] = R_GetTexture(normalmaptexture);
2000 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2001 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2002 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2003 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2004 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2005 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2006 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2007 m.pointer_texcoord_bufferobject[1] = 0;
2008 m.pointer_texcoord_bufferoffset[1] = 0;
2009 R_Mesh_TextureState(&m);
2010 GL_ColorMask(0,0,0,1);
2011 // this squares the result
2012 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2013 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2015 // second and third pass
2016 R_Mesh_ResetTextureState();
2017 // square alpha in framebuffer a few times to make it shiny
2018 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2019 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2020 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2023 memset(&m, 0, sizeof(m));
2024 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2025 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2026 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2027 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2028 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2029 R_Mesh_TextureState(&m);
2030 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2031 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2034 memset(&m, 0, sizeof(m));
2035 m.tex[0] = R_GetTexture(glosstexture);
2036 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2037 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2038 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2039 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2040 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2042 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2043 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2044 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2045 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2046 m.texmatrix[1] = rsurface.entitytolight;
2048 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2050 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2052 // 2/0/0/2 3D combine blendsquare path
2053 memset(&m, 0, sizeof(m));
2054 m.tex[0] = R_GetTexture(normalmaptexture);
2055 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2056 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2057 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2058 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2059 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2060 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2061 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2062 m.pointer_texcoord_bufferobject[1] = 0;
2063 m.pointer_texcoord_bufferoffset[1] = 0;
2064 R_Mesh_TextureState(&m);
2065 GL_ColorMask(0,0,0,1);
2066 // this squares the result
2067 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2068 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2070 // second and third pass
2071 R_Mesh_ResetTextureState();
2072 // square alpha in framebuffer a few times to make it shiny
2073 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2074 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2075 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2078 memset(&m, 0, sizeof(m));
2079 m.tex[0] = R_GetTexture(glosstexture);
2080 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2081 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2082 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2083 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2084 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2085 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2086 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2087 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2088 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2089 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2093 // 2/0/0/2/2 2D combine blendsquare path
2094 memset(&m, 0, sizeof(m));
2095 m.tex[0] = R_GetTexture(normalmaptexture);
2096 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2097 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2098 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2099 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2100 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2101 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2102 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2103 m.pointer_texcoord_bufferobject[1] = 0;
2104 m.pointer_texcoord_bufferoffset[1] = 0;
2105 R_Mesh_TextureState(&m);
2106 GL_ColorMask(0,0,0,1);
2107 // this squares the result
2108 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2109 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2111 // second and third pass
2112 R_Mesh_ResetTextureState();
2113 // square alpha in framebuffer a few times to make it shiny
2114 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2115 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2116 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2119 memset(&m, 0, sizeof(m));
2120 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2121 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2122 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2123 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2124 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2125 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2126 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2127 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2128 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2129 m.texmatrix[1] = rsurface.entitytoattenuationz;
2130 R_Mesh_TextureState(&m);
2131 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2132 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2135 memset(&m, 0, sizeof(m));
2136 m.tex[0] = R_GetTexture(glosstexture);
2137 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2138 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2139 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2140 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2141 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2143 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2144 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2145 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2146 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2147 m.texmatrix[1] = rsurface.entitytolight;
2149 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2151 // this final code is shared
2152 R_Mesh_TextureState(&m);
2153 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);
2156 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)
2158 // ARB path (any Geforce, any Radeon)
2159 qboolean doambient = ambientscale > 0;
2160 qboolean dodiffuse = diffusescale > 0;
2161 qboolean dospecular = specularscale > 0;
2162 if (!doambient && !dodiffuse && !dospecular)
2164 R_Mesh_ColorPointer(NULL, 0, 0);
2166 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
2168 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2172 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
2174 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2179 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
2181 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2184 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
2187 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2194 int newnumtriangles;
2198 int maxtriangles = 4096;
2199 int newelements[4096*3];
2200 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2201 for (renders = 0;renders < 64;renders++)
2206 newnumtriangles = 0;
2208 // due to low fillrate on the cards this vertex lighting path is
2209 // designed for, we manually cull all triangles that do not
2210 // contain a lit vertex
2211 // this builds batches of triangles from multiple surfaces and
2212 // renders them at once
2213 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2215 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2217 if (newnumtriangles)
2219 newfirstvertex = min(newfirstvertex, e[0]);
2220 newlastvertex = max(newlastvertex, e[0]);
2224 newfirstvertex = e[0];
2225 newlastvertex = e[0];
2227 newfirstvertex = min(newfirstvertex, e[1]);
2228 newlastvertex = max(newlastvertex, e[1]);
2229 newfirstvertex = min(newfirstvertex, e[2]);
2230 newlastvertex = max(newlastvertex, e[2]);
2236 if (newnumtriangles >= maxtriangles)
2238 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2239 newnumtriangles = 0;
2245 if (newnumtriangles >= 1)
2247 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2250 // if we couldn't find any lit triangles, exit early
2253 // now reduce the intensity for the next overbright pass
2254 // we have to clamp to 0 here incase the drivers have improper
2255 // handling of negative colors
2256 // (some old drivers even have improper handling of >1 color)
2258 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2260 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2262 c[0] = max(0, c[0] - 1);
2263 c[1] = max(0, c[1] - 1);
2264 c[2] = max(0, c[2] - 1);
2276 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)
2278 // OpenGL 1.1 path (anything)
2279 float ambientcolorbase[3], diffusecolorbase[3];
2280 float ambientcolorpants[3], diffusecolorpants[3];
2281 float ambientcolorshirt[3], diffusecolorshirt[3];
2283 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
2284 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
2285 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
2286 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
2287 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
2288 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
2289 memset(&m, 0, sizeof(m));
2290 m.tex[0] = R_GetTexture(basetexture);
2291 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2292 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2293 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2294 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2295 if (r_textureunits.integer >= 2)
2298 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2299 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2300 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2301 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2302 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2303 if (r_textureunits.integer >= 3)
2305 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2306 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2307 m.texmatrix[2] = rsurface.entitytoattenuationz;
2308 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2309 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2310 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2313 R_Mesh_TextureState(&m);
2314 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2315 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2318 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2319 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2323 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2324 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2328 extern cvar_t gl_lightmaps;
2329 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)
2331 float ambientscale, diffusescale, specularscale;
2332 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2334 // calculate colors to render this texture with
2335 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2336 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2337 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2338 ambientscale = rsurface.rtlight->ambientscale;
2339 diffusescale = rsurface.rtlight->diffusescale;
2340 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2341 if (!r_shadow_usenormalmap.integer)
2343 ambientscale += 1.0f * diffusescale;
2347 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2349 RSurf_SetupDepthAndCulling();
2350 nmap = rsurface.texture->currentskinframe->nmap;
2351 if (gl_lightmaps.integer)
2352 nmap = r_texture_blanknormalmap;
2353 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
2355 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2356 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2359 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2360 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2361 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2364 VectorClear(lightcolorpants);
2367 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2368 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2369 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2372 VectorClear(lightcolorshirt);
2373 switch (r_shadow_rendermode)
2375 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2376 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2377 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);
2379 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2380 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);
2382 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2383 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);
2385 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2386 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);
2389 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2395 switch (r_shadow_rendermode)
2397 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2398 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2399 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);
2401 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2402 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);
2404 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2405 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);
2407 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2408 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);
2411 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2417 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)
2419 matrix4x4_t tempmatrix = *matrix;
2420 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2422 // if this light has been compiled before, free the associated data
2423 R_RTLight_Uncompile(rtlight);
2425 // clear it completely to avoid any lingering data
2426 memset(rtlight, 0, sizeof(*rtlight));
2428 // copy the properties
2429 rtlight->matrix_lighttoworld = tempmatrix;
2430 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2431 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2432 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2433 VectorCopy(color, rtlight->color);
2434 rtlight->cubemapname[0] = 0;
2435 if (cubemapname && cubemapname[0])
2436 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2437 rtlight->shadow = shadow;
2438 rtlight->corona = corona;
2439 rtlight->style = style;
2440 rtlight->isstatic = isstatic;
2441 rtlight->coronasizescale = coronasizescale;
2442 rtlight->ambientscale = ambientscale;
2443 rtlight->diffusescale = diffusescale;
2444 rtlight->specularscale = specularscale;
2445 rtlight->flags = flags;
2447 // compute derived data
2448 //rtlight->cullradius = rtlight->radius;
2449 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2450 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2451 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2452 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2453 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2454 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2455 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2458 // compiles rtlight geometry
2459 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2460 void R_RTLight_Compile(rtlight_t *rtlight)
2463 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2464 int lighttris, shadowtris, shadowmeshes, shadowmeshtris;
2465 entity_render_t *ent = r_refdef.scene.worldentity;
2466 dp_model_t *model = r_refdef.scene.worldmodel;
2467 unsigned char *data;
2469 // compile the light
2470 rtlight->compiled = true;
2471 rtlight->static_numleafs = 0;
2472 rtlight->static_numleafpvsbytes = 0;
2473 rtlight->static_leaflist = NULL;
2474 rtlight->static_leafpvs = NULL;
2475 rtlight->static_numsurfaces = 0;
2476 rtlight->static_surfacelist = NULL;
2477 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2478 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2479 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2480 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2481 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2482 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2484 if (model && model->GetLightInfo)
2486 // this variable must be set for the CompileShadowVolume code
2487 r_shadow_compilingrtlight = rtlight;
2488 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);
2489 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);
2490 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2491 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2492 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2493 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2494 rtlight->static_numsurfaces = numsurfaces;
2495 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2496 rtlight->static_numleafs = numleafs;
2497 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2498 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2499 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2500 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2501 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2502 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2503 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2504 if (rtlight->static_numsurfaces)
2505 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2506 if (rtlight->static_numleafs)
2507 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2508 if (rtlight->static_numleafpvsbytes)
2509 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2510 if (rtlight->static_numshadowtrispvsbytes)
2511 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2512 if (rtlight->static_numlighttrispvsbytes)
2513 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2514 if (model->CompileShadowVolume && rtlight->shadow)
2515 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2516 // now we're done compiling the rtlight
2517 r_shadow_compilingrtlight = NULL;
2521 // use smallest available cullradius - box radius or light radius
2522 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2523 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2527 if (rtlight->static_meshchain_shadow)
2530 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2533 shadowmeshtris += mesh->numtriangles;
2538 if (rtlight->static_numlighttrispvsbytes)
2539 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2540 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2544 if (rtlight->static_numlighttrispvsbytes)
2545 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2546 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2549 if (developer.integer >= 10)
2550 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);
2553 void R_RTLight_Uncompile(rtlight_t *rtlight)
2555 if (rtlight->compiled)
2557 if (rtlight->static_meshchain_shadow)
2558 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2559 rtlight->static_meshchain_shadow = NULL;
2560 // these allocations are grouped
2561 if (rtlight->static_surfacelist)
2562 Mem_Free(rtlight->static_surfacelist);
2563 rtlight->static_numleafs = 0;
2564 rtlight->static_numleafpvsbytes = 0;
2565 rtlight->static_leaflist = NULL;
2566 rtlight->static_leafpvs = NULL;
2567 rtlight->static_numsurfaces = 0;
2568 rtlight->static_surfacelist = NULL;
2569 rtlight->static_numshadowtrispvsbytes = 0;
2570 rtlight->static_shadowtrispvs = NULL;
2571 rtlight->static_numlighttrispvsbytes = 0;
2572 rtlight->static_lighttrispvs = NULL;
2573 rtlight->compiled = false;
2577 void R_Shadow_UncompileWorldLights(void)
2581 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2582 for (lightindex = 0;lightindex < range;lightindex++)
2584 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2587 R_RTLight_Uncompile(&light->rtlight);
2591 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2595 // reset the count of frustum planes
2596 // see rsurface.rtlight_frustumplanes definition for how much this array
2598 rsurface.rtlight_numfrustumplanes = 0;
2600 // haven't implemented a culling path for ortho rendering
2601 if (!r_refdef.view.useperspective)
2603 // check if the light is on screen and copy the 4 planes if it is
2604 for (i = 0;i < 4;i++)
2605 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2608 for (i = 0;i < 4;i++)
2609 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
2614 // generate a deformed frustum that includes the light origin, this is
2615 // used to cull shadow casting surfaces that can not possibly cast a
2616 // shadow onto the visible light-receiving surfaces, which can be a
2619 // if the light origin is onscreen the result will be 4 planes exactly
2620 // if the light origin is offscreen on only one axis the result will
2621 // be exactly 5 planes (split-side case)
2622 // if the light origin is offscreen on two axes the result will be
2623 // exactly 4 planes (stretched corner case)
2624 for (i = 0;i < 4;i++)
2626 // quickly reject standard frustum planes that put the light
2627 // origin outside the frustum
2628 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2631 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
2633 // if all the standard frustum planes were accepted, the light is onscreen
2634 // otherwise we need to generate some more planes below...
2635 if (rsurface.rtlight_numfrustumplanes < 4)
2637 // at least one of the stock frustum planes failed, so we need to
2638 // create one or two custom planes to enclose the light origin
2639 for (i = 0;i < 4;i++)
2641 // create a plane using the view origin and light origin, and a
2642 // single point from the frustum corner set
2643 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2644 VectorNormalize(plane.normal);
2645 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
2646 // see if this plane is backwards and flip it if so
2647 for (j = 0;j < 4;j++)
2648 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2652 VectorNegate(plane.normal, plane.normal);
2654 // flipped plane, test again to see if it is now valid
2655 for (j = 0;j < 4;j++)
2656 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2658 // if the plane is still not valid, then it is dividing the
2659 // frustum and has to be rejected
2663 // we have created a valid plane, compute extra info
2664 PlaneClassify(&plane);
2666 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2668 // if we've found 5 frustum planes then we have constructed a
2669 // proper split-side case and do not need to keep searching for
2670 // planes to enclose the light origin
2671 if (rsurface.rtlight_numfrustumplanes == 5)
2679 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
2681 plane = rsurface.rtlight_frustumplanes[i];
2682 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));
2687 // now add the light-space box planes if the light box is rotated, as any
2688 // caster outside the oriented light box is irrelevant (even if it passed
2689 // the worldspace light box, which is axial)
2690 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
2692 for (i = 0;i < 6;i++)
2696 v[i >> 1] = (i & 1) ? -1 : 1;
2697 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
2698 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
2699 plane.dist = VectorNormalizeLength(plane.normal);
2700 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
2701 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2707 // add the world-space reduced box planes
2708 for (i = 0;i < 6;i++)
2710 VectorClear(plane.normal);
2711 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
2712 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
2713 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2722 // reduce all plane distances to tightly fit the rtlight cull box, which
2724 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2725 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2726 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2727 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2728 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2729 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2730 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2731 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2732 oldnum = rsurface.rtlight_numfrustumplanes;
2733 rsurface.rtlight_numfrustumplanes = 0;
2734 for (j = 0;j < oldnum;j++)
2736 // find the nearest point on the box to this plane
2737 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
2738 for (i = 1;i < 8;i++)
2740 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
2741 if (bestdist > dist)
2744 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);
2745 // if the nearest point is near or behind the plane, we want this
2746 // plane, otherwise the plane is useless as it won't cull anything
2747 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
2749 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
2750 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
2757 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2759 RSurf_ActiveWorldEntity();
2760 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2764 for (mesh = rsurface.rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2766 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2767 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
2768 GL_LockArrays(0, mesh->numverts);
2769 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2771 // decrement stencil if backface is behind depthbuffer
2772 GL_CullFace(r_refdef.view.cullface_front);
2773 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2774 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
2775 // increment stencil if frontface is behind depthbuffer
2776 GL_CullFace(r_refdef.view.cullface_back);
2777 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2779 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
2780 GL_LockArrays(0, 0);
2784 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
2787 int surfacelistindex;
2788 msurface_t *surface;
2789 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
2790 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2792 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
2793 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
2794 if (CHECKPVSBIT(trispvs, t))
2795 shadowmarklist[numshadowmark++] = t;
2797 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, r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
2799 else if (numsurfaces)
2800 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
2803 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
2805 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2806 vec_t relativeshadowradius;
2807 RSurf_ActiveModelEntity(ent, false, false);
2808 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
2809 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
2810 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2811 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2812 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2813 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2814 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2815 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2816 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2819 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2821 // set up properties for rendering light onto this entity
2822 RSurf_ActiveModelEntity(ent, true, true);
2823 GL_AlphaTest(false);
2824 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
2825 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2826 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2827 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2828 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2829 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2832 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2834 if (!r_refdef.scene.worldmodel->DrawLight)
2837 // set up properties for rendering light onto this entity
2838 RSurf_ActiveWorldEntity();
2839 GL_AlphaTest(false);
2840 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
2841 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2842 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2843 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2844 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2845 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2847 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
2850 void R_Shadow_DrawEntityLight(entity_render_t *ent)
2852 dp_model_t *model = ent->model;
2853 if (!model->DrawLight)
2856 R_Shadow_SetupEntityLight(ent);
2858 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist, NULL);
2861 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2865 int numleafs, numsurfaces;
2866 int *leaflist, *surfacelist;
2867 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
2868 int numlightentities;
2869 int numlightentities_noselfshadow;
2870 int numshadowentities;
2871 int numshadowentities_noselfshadow;
2872 static entity_render_t *lightentities[MAX_EDICTS];
2873 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
2874 static entity_render_t *shadowentities[MAX_EDICTS];
2875 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
2877 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2878 // skip lights that are basically invisible (color 0 0 0)
2879 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2882 // loading is done before visibility checks because loading should happen
2883 // all at once at the start of a level, not when it stalls gameplay.
2884 // (especially important to benchmarks)
2886 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2887 R_RTLight_Compile(rtlight);
2889 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2891 // look up the light style value at this time
2892 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
2893 VectorScale(rtlight->color, f, rtlight->currentcolor);
2895 if (rtlight->selected)
2897 f = 2 + sin(realtime * M_PI * 4.0);
2898 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2902 // if lightstyle is currently off, don't draw the light
2903 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2906 // if the light box is offscreen, skip it
2907 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2910 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
2911 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
2913 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2915 // compiled light, world available and can receive realtime lighting
2916 // retrieve leaf information
2917 numleafs = rtlight->static_numleafs;
2918 leaflist = rtlight->static_leaflist;
2919 leafpvs = rtlight->static_leafpvs;
2920 numsurfaces = rtlight->static_numsurfaces;
2921 surfacelist = rtlight->static_surfacelist;
2922 shadowtrispvs = rtlight->static_shadowtrispvs;
2923 lighttrispvs = rtlight->static_lighttrispvs;
2925 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
2927 // dynamic light, world available and can receive realtime lighting
2928 // calculate lit surfaces and leafs
2929 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);
2930 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);
2931 leaflist = r_shadow_buffer_leaflist;
2932 leafpvs = r_shadow_buffer_leafpvs;
2933 surfacelist = r_shadow_buffer_surfacelist;
2934 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
2935 lighttrispvs = r_shadow_buffer_lighttrispvs;
2936 // if the reduced leaf bounds are offscreen, skip it
2937 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2948 shadowtrispvs = NULL;
2949 lighttrispvs = NULL;
2951 // check if light is illuminating any visible leafs
2954 for (i = 0;i < numleafs;i++)
2955 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
2960 // set up a scissor rectangle for this light
2961 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2964 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
2966 // make a list of lit entities and shadow casting entities
2967 numlightentities = 0;
2968 numlightentities_noselfshadow = 0;
2969 numshadowentities = 0;
2970 numshadowentities_noselfshadow = 0;
2971 // add dynamic entities that are lit by the light
2972 if (r_drawentities.integer)
2974 for (i = 0;i < r_refdef.scene.numentities;i++)
2977 entity_render_t *ent = r_refdef.scene.entities[i];
2979 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2981 // skip the object entirely if it is not within the valid
2982 // shadow-casting region (which includes the lit region)
2983 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
2985 if (!(model = ent->model))
2987 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
2989 // this entity wants to receive light, is visible, and is
2990 // inside the light box
2991 // TODO: check if the surfaces in the model can receive light
2992 // so now check if it's in a leaf seen by the light
2993 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))
2995 if (ent->flags & RENDER_NOSELFSHADOW)
2996 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
2998 lightentities[numlightentities++] = ent;
2999 // since it is lit, it probably also casts a shadow...
3000 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3001 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3002 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3004 // note: exterior models without the RENDER_NOSELFSHADOW
3005 // flag still create a RENDER_NOSELFSHADOW shadow but
3006 // are lit normally, this means that they are
3007 // self-shadowing but do not shadow other
3008 // RENDER_NOSELFSHADOW entities such as the gun
3009 // (very weird, but keeps the player shadow off the gun)
3010 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3011 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3013 shadowentities[numshadowentities++] = ent;
3016 else if (ent->flags & RENDER_SHADOW)
3018 // this entity is not receiving light, but may still need to
3020 // TODO: check if the surfaces in the model can cast shadow
3021 // now check if it is in a leaf seen by the light
3022 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))
3024 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3025 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3026 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3028 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3029 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3031 shadowentities[numshadowentities++] = ent;
3037 // return if there's nothing at all to light
3038 if (!numlightentities && !numsurfaces)
3041 // don't let sound skip if going slow
3042 if (r_refdef.scene.extraupdate)
3045 // make this the active rtlight for rendering purposes
3046 R_Shadow_RenderMode_ActiveLight(rtlight);
3047 // count this light in the r_speeds
3048 r_refdef.stats.lights++;
3050 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3052 // optionally draw visible shape of the shadow volumes
3053 // for performance analysis by level designers
3054 R_Shadow_RenderMode_VisibleShadowVolumes();
3056 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3057 for (i = 0;i < numshadowentities;i++)
3058 R_Shadow_DrawEntityShadow(shadowentities[i]);
3059 for (i = 0;i < numshadowentities_noselfshadow;i++)
3060 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3063 if (gl_stencil && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3065 // draw stencil shadow volumes to mask off pixels that are in shadow
3066 // so that they won't receive lighting
3067 R_Shadow_ClearStencil();
3068 R_Shadow_RenderMode_StencilShadowVolumes();
3070 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3071 for (i = 0;i < numshadowentities;i++)
3072 R_Shadow_DrawEntityShadow(shadowentities[i]);
3073 if (numlightentities_noselfshadow)
3075 // draw lighting in the unmasked areas
3076 R_Shadow_RenderMode_Lighting(true, false);
3077 for (i = 0;i < numlightentities_noselfshadow;i++)
3078 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3080 // optionally draw the illuminated areas
3081 // for performance analysis by level designers
3082 if (r_showlighting.integer && r_refdef.view.showdebug)
3084 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3085 for (i = 0;i < numlightentities_noselfshadow;i++)
3086 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3089 R_Shadow_RenderMode_StencilShadowVolumes();
3091 for (i = 0;i < numshadowentities_noselfshadow;i++)
3092 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3094 if (numsurfaces + numlightentities)
3096 // draw lighting in the unmasked areas
3097 R_Shadow_RenderMode_Lighting(true, false);
3099 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3100 for (i = 0;i < numlightentities;i++)
3101 R_Shadow_DrawEntityLight(lightentities[i]);
3103 // optionally draw the illuminated areas
3104 // for performance analysis by level designers
3105 if (r_showlighting.integer && r_refdef.view.showdebug)
3107 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3109 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3110 for (i = 0;i < numlightentities;i++)
3111 R_Shadow_DrawEntityLight(lightentities[i]);
3117 if (numsurfaces + numlightentities)
3119 // draw lighting in the unmasked areas
3120 R_Shadow_RenderMode_Lighting(false, false);
3122 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3123 for (i = 0;i < numlightentities;i++)
3124 R_Shadow_DrawEntityLight(lightentities[i]);
3125 for (i = 0;i < numlightentities_noselfshadow;i++)
3126 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3128 // optionally draw the illuminated areas
3129 // for performance analysis by level designers
3130 if (r_showlighting.integer && r_refdef.view.showdebug)
3132 R_Shadow_RenderMode_VisibleLighting(false, false);
3134 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3135 for (i = 0;i < numlightentities;i++)
3136 R_Shadow_DrawEntityLight(lightentities[i]);
3137 for (i = 0;i < numlightentities_noselfshadow;i++)
3138 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3144 void R_Shadow_DrawLightSprites(void);
3145 void R_ShadowVolumeLighting(qboolean visible)
3153 if (r_editlights.integer)
3154 R_Shadow_DrawLightSprites();
3156 R_Shadow_RenderMode_Begin();
3158 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3159 if (r_shadow_debuglight.integer >= 0)
3161 lightindex = r_shadow_debuglight.integer;
3162 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3163 if (light && (light->flags & flag))
3164 R_DrawRTLight(&light->rtlight, visible);
3168 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3169 for (lightindex = 0;lightindex < range;lightindex++)
3171 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3172 if (light && (light->flags & flag))
3173 R_DrawRTLight(&light->rtlight, visible);
3176 if (r_refdef.scene.rtdlight)
3177 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3178 R_DrawRTLight(&r_refdef.scene.lights[lnum], visible);
3180 R_Shadow_RenderMode_End();
3183 extern void R_SetupView(qboolean allowwaterclippingplane);
3184 extern cvar_t r_shadows;
3185 extern cvar_t r_shadows_throwdistance;
3186 void R_DrawModelShadows(void)
3189 float relativethrowdistance;
3190 entity_render_t *ent;
3191 vec3_t relativelightorigin;
3192 vec3_t relativelightdirection;
3193 vec3_t relativeshadowmins, relativeshadowmaxs;
3197 if (!r_drawentities.integer || !gl_stencil)
3201 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3203 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3205 if (gl_ext_separatestencil.integer)
3206 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
3207 else if (gl_ext_stenciltwoside.integer)
3208 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
3210 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
3212 R_Shadow_ClearStencil();
3213 R_Shadow_RenderMode_StencilShadowVolumes();
3215 for (i = 0;i < r_refdef.scene.numentities;i++)
3217 ent = r_refdef.scene.entities[i];
3218 // cast shadows from anything that is not a submodel of the map
3219 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
3221 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3222 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3223 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3225 if(r_shadows.integer == 2)
3227 // 2: simpler mode, throw shadows always DOWN
3228 VectorSet(tmp, 0, 0, -1);
3229 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
3233 if(ent->entitynumber != 0)
3235 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
3236 int entnum, entnum2, recursion;
3237 entnum = entnum2 = ent->entitynumber;
3238 for(recursion = 32; recursion > 0; --recursion)
3240 entnum2 = cl.entities[entnum].state_current.tagentity;
3241 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
3246 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
3248 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
3249 // transform into modelspace of OUR entity
3250 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
3251 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
3254 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3257 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3260 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3261 RSurf_ActiveModelEntity(ent, false, false);
3262 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
3266 // not really the right mode, but this will disable any silly stencil features
3267 R_Shadow_RenderMode_VisibleLighting(true, true);
3269 // vertex coordinates for a quad that covers the screen exactly
3270 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
3271 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
3272 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
3273 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
3275 // set up ortho view for rendering this pass
3276 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
3277 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3278 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3279 GL_ScissorTest(true);
3280 R_Mesh_Matrix(&identitymatrix);
3281 R_Mesh_ResetTextureState();
3282 R_Mesh_VertexPointer(vertex3f, 0, 0);
3283 R_Mesh_ColorPointer(NULL, 0, 0);
3285 // set up a 50% darkening blend on shadowed areas
3286 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3287 GL_DepthRange(0, 1);
3288 GL_DepthTest(false);
3289 GL_DepthMask(false);
3290 GL_PolygonOffset(0, 0);CHECKGLERROR
3291 GL_Color(0, 0, 0, 0.5);
3292 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3293 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
3294 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
3295 qglStencilMask(~0);CHECKGLERROR
3296 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3297 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
3299 // apply the blend to the shadowed areas
3300 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
3302 // restoring the perspective view is done by R_RenderScene
3303 //R_SetupView(true);
3305 // restore other state to normal
3306 R_Shadow_RenderMode_End();
3309 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
3311 // if it's too close, skip it
3312 if (VectorLength(rtlight->color) < (1.0f / 256.0f))
3314 if (VectorDistance2(rtlight->shadoworigin, r_refdef.view.origin) < 32.0f * 32.0f)
3316 if (usequery && r_numqueries + 2 <= r_maxqueries)
3318 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
3319 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
3321 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
3322 R_DrawSprite(GL_ONE, GL_ZERO, r_shadow_lightcorona, NULL, true, false, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, 1, 1, 1, 1);
3323 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
3324 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
3325 R_DrawSprite(GL_ONE, GL_ZERO, r_shadow_lightcorona, NULL, false, false, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, 1, 1, 1, 1);
3326 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
3329 rtlight->corona_visibility = 1;
3332 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
3335 GLint allpixels = 0, visiblepixels = 0;
3336 // now we have to check the query result
3337 if (rtlight->corona_queryindex_visiblepixels)
3340 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
3341 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
3343 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
3344 if (visiblepixels < 1 || allpixels < 1)
3346 rtlight->corona_visibility *= (float)visiblepixels / (float)allpixels;
3347 cscale *= rtlight->corona_visibility;
3351 // FIXME: these traces should scan all render entities instead of cl.world
3352 if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
3355 VectorScale(rtlight->color, cscale, color);
3356 if (VectorLength(color) > (1.0f / 256.0f))
3357 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, color[0], color[1], color[2], 1);
3360 void R_DrawCoronas(void)
3368 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
3370 if (r_waterstate.renderingscene)
3372 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3373 R_Mesh_Matrix(&identitymatrix);
3375 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3377 // check occlusion of coronas
3378 // use GL_ARB_occlusion_query if available
3379 // otherwise use raytraces
3381 usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
3384 GL_ColorMask(0,0,0,0);
3385 if (r_maxqueries < range + r_refdef.scene.numlights)
3386 if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
3389 r_maxqueries = (range + r_refdef.scene.numlights) * 2;
3390 r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
3392 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
3396 for (lightindex = 0;lightindex < range;lightindex++)
3398 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3401 rtlight = &light->rtlight;
3402 rtlight->corona_visibility = 0;
3403 rtlight->corona_queryindex_visiblepixels = 0;
3404 rtlight->corona_queryindex_allpixels = 0;
3405 if (!(rtlight->flags & flag))
3407 if (rtlight->corona <= 0)
3409 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
3411 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
3413 for (i = 0;i < r_refdef.scene.numlights;i++)
3415 rtlight = &r_refdef.scene.lights[i];
3416 rtlight->corona_visibility = 0;
3417 rtlight->corona_queryindex_visiblepixels = 0;
3418 rtlight->corona_queryindex_allpixels = 0;
3419 if (!(rtlight->flags & flag))
3421 if (rtlight->corona <= 0)
3423 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
3426 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3428 // now draw the coronas using the query data for intensity info
3429 for (lightindex = 0;lightindex < range;lightindex++)
3431 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3434 rtlight = &light->rtlight;
3435 if (rtlight->corona_visibility <= 0)
3437 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
3439 for (i = 0;i < r_refdef.scene.numlights;i++)
3441 rtlight = &r_refdef.scene.lights[i];
3442 if (rtlight->corona_visibility <= 0)
3444 if (gl_flashblend.integer)
3445 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
3447 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
3453 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3454 typedef struct suffixinfo_s
3457 qboolean flipx, flipy, flipdiagonal;
3460 static suffixinfo_t suffix[3][6] =
3463 {"px", false, false, false},
3464 {"nx", false, false, false},
3465 {"py", false, false, false},
3466 {"ny", false, false, false},
3467 {"pz", false, false, false},
3468 {"nz", false, false, false}
3471 {"posx", false, false, false},
3472 {"negx", false, false, false},
3473 {"posy", false, false, false},
3474 {"negy", false, false, false},
3475 {"posz", false, false, false},
3476 {"negz", false, false, false}
3479 {"rt", true, false, true},
3480 {"lf", false, true, true},
3481 {"ft", true, true, false},
3482 {"bk", false, false, false},
3483 {"up", true, false, true},
3484 {"dn", true, false, true}
3488 static int componentorder[4] = {0, 1, 2, 3};
3490 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3492 int i, j, cubemapsize;
3493 unsigned char *cubemappixels, *image_buffer;
3494 rtexture_t *cubemaptexture;
3496 // must start 0 so the first loadimagepixels has no requested width/height
3498 cubemappixels = NULL;
3499 cubemaptexture = NULL;
3500 // keep trying different suffix groups (posx, px, rt) until one loads
3501 for (j = 0;j < 3 && !cubemappixels;j++)
3503 // load the 6 images in the suffix group
3504 for (i = 0;i < 6;i++)
3506 // generate an image name based on the base and and suffix
3507 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3509 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
3511 // an image loaded, make sure width and height are equal
3512 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
3514 // if this is the first image to load successfully, allocate the cubemap memory
3515 if (!cubemappixels && image_width >= 1)
3517 cubemapsize = image_width;
3518 // note this clears to black, so unavailable sides are black
3519 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3521 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3523 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);
3526 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3528 Mem_Free(image_buffer);
3532 // if a cubemap loaded, upload it
3535 if (developer_loading.integer)
3536 Con_Printf("loading cubemap \"%s\"\n", basename);
3538 if (!r_shadow_filters_texturepool)
3539 r_shadow_filters_texturepool = R_AllocTexturePool();
3540 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0), NULL);
3541 Mem_Free(cubemappixels);
3545 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
3546 if (developer_loading.integer)
3548 Con_Printf("(tried tried images ");
3549 for (j = 0;j < 3;j++)
3550 for (i = 0;i < 6;i++)
3551 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3552 Con_Print(" and was unable to find any of them).\n");
3555 return cubemaptexture;
3558 rtexture_t *R_Shadow_Cubemap(const char *basename)
3561 for (i = 0;i < numcubemaps;i++)
3562 if (!strcasecmp(cubemaps[i].basename, basename))
3563 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
3564 if (i >= MAX_CUBEMAPS)
3565 return r_texture_whitecube;
3567 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
3568 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3569 return cubemaps[i].texture;
3572 void R_Shadow_FreeCubemaps(void)
3575 for (i = 0;i < numcubemaps;i++)
3577 if (developer_loading.integer)
3578 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
3579 if (cubemaps[i].texture)
3580 R_FreeTexture(cubemaps[i].texture);
3584 R_FreeTexturePool(&r_shadow_filters_texturepool);
3587 dlight_t *R_Shadow_NewWorldLight(void)
3589 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
3592 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)
3595 // validate parameters
3596 if (style < 0 || style >= MAX_LIGHTSTYLES)
3598 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3604 // copy to light properties
3605 VectorCopy(origin, light->origin);
3606 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3607 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3608 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3609 light->color[0] = max(color[0], 0);
3610 light->color[1] = max(color[1], 0);
3611 light->color[2] = max(color[2], 0);
3612 light->radius = max(radius, 0);
3613 light->style = style;
3614 light->shadow = shadowenable;
3615 light->corona = corona;
3616 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3617 light->coronasizescale = coronasizescale;
3618 light->ambientscale = ambientscale;
3619 light->diffusescale = diffusescale;
3620 light->specularscale = specularscale;
3621 light->flags = flags;
3623 // update renderable light data
3624 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
3625 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);
3628 void R_Shadow_FreeWorldLight(dlight_t *light)
3630 if (r_shadow_selectedlight == light)
3631 r_shadow_selectedlight = NULL;
3632 R_RTLight_Uncompile(&light->rtlight);
3633 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
3636 void R_Shadow_ClearWorldLights(void)
3640 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3641 for (lightindex = 0;lightindex < range;lightindex++)
3643 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3645 R_Shadow_FreeWorldLight(light);
3647 r_shadow_selectedlight = NULL;
3648 R_Shadow_FreeCubemaps();
3651 void R_Shadow_SelectLight(dlight_t *light)
3653 if (r_shadow_selectedlight)
3654 r_shadow_selectedlight->selected = false;
3655 r_shadow_selectedlight = light;
3656 if (r_shadow_selectedlight)
3657 r_shadow_selectedlight->selected = true;
3660 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3662 // this is never batched (there can be only one)
3663 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);
3666 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3673 // this is never batched (due to the ent parameter changing every time)
3674 // so numsurfaces == 1 and surfacelist[0] == lightnumber
3675 const dlight_t *light = (dlight_t *)ent;
3678 VectorScale(light->color, intensity, spritecolor);
3679 if (VectorLength(spritecolor) < 0.1732f)
3680 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
3681 if (VectorLength(spritecolor) > 1.0f)
3682 VectorNormalize(spritecolor);
3684 // draw light sprite
3685 if (light->cubemapname[0] && !light->shadow)
3686 pic = r_editlights_sprcubemapnoshadowlight;
3687 else if (light->cubemapname[0])
3688 pic = r_editlights_sprcubemaplight;
3689 else if (!light->shadow)
3690 pic = r_editlights_sprnoshadowlight;
3692 pic = r_editlights_sprlight;
3693 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);
3694 // draw selection sprite if light is selected
3695 if (light->selected)
3696 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);
3697 // VorteX todo: add normalmode/realtime mode light overlay sprites?
3700 void R_Shadow_DrawLightSprites(void)
3704 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3705 for (lightindex = 0;lightindex < range;lightindex++)
3707 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3709 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
3711 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
3714 void R_Shadow_SelectLightInView(void)
3716 float bestrating, rating, temp[3];
3720 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3723 for (lightindex = 0;lightindex < range;lightindex++)
3725 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3728 VectorSubtract(light->origin, r_refdef.view.origin, temp);
3729 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
3732 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3733 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)
3735 bestrating = rating;
3740 R_Shadow_SelectLight(best);
3743 void R_Shadow_LoadWorldLights(void)
3745 int n, a, style, shadow, flags;
3746 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3747 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3748 if (cl.worldmodel == NULL)
3750 Con_Print("No map loaded.\n");
3753 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
3754 strlcat (name, ".rtlights", sizeof (name));
3755 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3765 for (;COM_Parse(t, true) && strcmp(
3766 if (COM_Parse(t, true))
3768 if (com_token[0] == '!')
3771 origin[0] = atof(com_token+1);
3774 origin[0] = atof(com_token);
3779 while (*s && *s != '\n' && *s != '\r')
3785 // check for modifier flags
3792 #if _MSC_VER >= 1400
3793 #define sscanf sscanf_s
3795 cubemapname[sizeof(cubemapname)-1] = 0;
3796 #if MAX_QPATH != 128
3797 #error update this code if MAX_QPATH changes
3799 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
3800 #if _MSC_VER >= 1400
3801 , sizeof(cubemapname)
3803 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
3806 flags = LIGHTFLAG_REALTIMEMODE;
3814 coronasizescale = 0.25f;
3816 VectorClear(angles);
3819 if (a < 9 || !strcmp(cubemapname, "\"\""))
3821 // remove quotes on cubemapname
3822 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3825 namelen = strlen(cubemapname) - 2;
3826 memmove(cubemapname, cubemapname + 1, namelen);
3827 cubemapname[namelen] = '\0';
3831 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);
3834 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3842 Con_Printf("invalid rtlights file \"%s\"\n", name);
3843 Mem_Free(lightsstring);
3847 void R_Shadow_SaveWorldLights(void)
3851 size_t bufchars, bufmaxchars;
3853 char name[MAX_QPATH];
3854 char line[MAX_INPUTLINE];
3855 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
3856 // I hate lines which are 3 times my screen size :( --blub
3859 if (cl.worldmodel == NULL)
3861 Con_Print("No map loaded.\n");
3864 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
3865 strlcat (name, ".rtlights", sizeof (name));
3866 bufchars = bufmaxchars = 0;
3868 for (lightindex = 0;lightindex < range;lightindex++)
3870 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3873 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3874 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);
3875 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3876 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]);
3878 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);
3879 if (bufchars + strlen(line) > bufmaxchars)
3881 bufmaxchars = bufchars + strlen(line) + 2048;
3883 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3887 memcpy(buf, oldbuf, bufchars);
3893 memcpy(buf + bufchars, line, strlen(line));
3894 bufchars += strlen(line);
3898 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3903 void R_Shadow_LoadLightsFile(void)
3906 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3907 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3908 if (cl.worldmodel == NULL)
3910 Con_Print("No map loaded.\n");
3913 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
3914 strlcat (name, ".lights", sizeof (name));
3915 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3923 while (*s && *s != '\n' && *s != '\r')
3929 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);
3933 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);
3936 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3937 radius = bound(15, radius, 4096);
3938 VectorScale(color, (2.0f / (8388608.0f)), color);
3939 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3947 Con_Printf("invalid lights file \"%s\"\n", name);
3948 Mem_Free(lightsstring);
3952 // tyrlite/hmap2 light types in the delay field
3953 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3955 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3957 int entnum, style, islight, skin, pflags, effects, type, n;
3960 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3961 char key[256], value[MAX_INPUTLINE];
3963 if (cl.worldmodel == NULL)
3965 Con_Print("No map loaded.\n");
3968 // try to load a .ent file first
3969 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
3970 strlcat (key, ".ent", sizeof (key));
3971 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3972 // and if that is not found, fall back to the bsp file entity string
3974 data = cl.worldmodel->brush.entities;
3977 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
3979 type = LIGHTTYPE_MINUSX;
3980 origin[0] = origin[1] = origin[2] = 0;
3981 originhack[0] = originhack[1] = originhack[2] = 0;
3982 angles[0] = angles[1] = angles[2] = 0;
3983 color[0] = color[1] = color[2] = 1;
3984 light[0] = light[1] = light[2] = 1;light[3] = 300;
3985 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3995 if (!COM_ParseToken_Simple(&data, false, false))
3997 if (com_token[0] == '}')
3998 break; // end of entity
3999 if (com_token[0] == '_')
4000 strlcpy(key, com_token + 1, sizeof(key));
4002 strlcpy(key, com_token, sizeof(key));
4003 while (key[strlen(key)-1] == ' ') // remove trailing spaces
4004 key[strlen(key)-1] = 0;
4005 if (!COM_ParseToken_Simple(&data, false, false))
4007 strlcpy(value, com_token, sizeof(value));
4009 // now that we have the key pair worked out...
4010 if (!strcmp("light", key))
4012 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
4016 light[0] = vec[0] * (1.0f / 256.0f);
4017 light[1] = vec[0] * (1.0f / 256.0f);
4018 light[2] = vec[0] * (1.0f / 256.0f);
4024 light[0] = vec[0] * (1.0f / 255.0f);
4025 light[1] = vec[1] * (1.0f / 255.0f);
4026 light[2] = vec[2] * (1.0f / 255.0f);
4030 else if (!strcmp("delay", key))
4032 else if (!strcmp("origin", key))
4033 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
4034 else if (!strcmp("angle", key))
4035 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
4036 else if (!strcmp("angles", key))
4037 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
4038 else if (!strcmp("color", key))
4039 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
4040 else if (!strcmp("wait", key))
4041 fadescale = atof(value);
4042 else if (!strcmp("classname", key))
4044 if (!strncmp(value, "light", 5))
4047 if (!strcmp(value, "light_fluoro"))
4052 overridecolor[0] = 1;
4053 overridecolor[1] = 1;
4054 overridecolor[2] = 1;
4056 if (!strcmp(value, "light_fluorospark"))
4061 overridecolor[0] = 1;
4062 overridecolor[1] = 1;
4063 overridecolor[2] = 1;
4065 if (!strcmp(value, "light_globe"))
4070 overridecolor[0] = 1;
4071 overridecolor[1] = 0.8;
4072 overridecolor[2] = 0.4;
4074 if (!strcmp(value, "light_flame_large_yellow"))
4079 overridecolor[0] = 1;
4080 overridecolor[1] = 0.5;
4081 overridecolor[2] = 0.1;
4083 if (!strcmp(value, "light_flame_small_yellow"))
4088 overridecolor[0] = 1;
4089 overridecolor[1] = 0.5;
4090 overridecolor[2] = 0.1;
4092 if (!strcmp(value, "light_torch_small_white"))
4097 overridecolor[0] = 1;
4098 overridecolor[1] = 0.5;
4099 overridecolor[2] = 0.1;
4101 if (!strcmp(value, "light_torch_small_walltorch"))
4106 overridecolor[0] = 1;
4107 overridecolor[1] = 0.5;
4108 overridecolor[2] = 0.1;
4112 else if (!strcmp("style", key))
4113 style = atoi(value);
4114 else if (!strcmp("skin", key))
4115 skin = (int)atof(value);
4116 else if (!strcmp("pflags", key))
4117 pflags = (int)atof(value);
4118 else if (!strcmp("effects", key))
4119 effects = (int)atof(value);
4120 else if (cl.worldmodel->type == mod_brushq3)
4122 if (!strcmp("scale", key))
4123 lightscale = atof(value);
4124 if (!strcmp("fade", key))
4125 fadescale = atof(value);
4130 if (lightscale <= 0)
4134 if (color[0] == color[1] && color[0] == color[2])
4136 color[0] *= overridecolor[0];
4137 color[1] *= overridecolor[1];
4138 color[2] *= overridecolor[2];
4140 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
4141 color[0] = color[0] * light[0];
4142 color[1] = color[1] * light[1];
4143 color[2] = color[2] * light[2];
4146 case LIGHTTYPE_MINUSX:
4148 case LIGHTTYPE_RECIPX:
4150 VectorScale(color, (1.0f / 16.0f), color);
4152 case LIGHTTYPE_RECIPXX:
4154 VectorScale(color, (1.0f / 16.0f), color);
4157 case LIGHTTYPE_NONE:
4161 case LIGHTTYPE_MINUSXX:
4164 VectorAdd(origin, originhack, origin);
4166 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);
4169 Mem_Free(entfiledata);
4173 void R_Shadow_SetCursorLocationForView(void)
4176 vec3_t dest, endpos;
4178 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
4179 trace = CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
4180 if (trace.fraction < 1)
4182 dist = trace.fraction * r_editlights_cursordistance.value;
4183 push = r_editlights_cursorpushback.value;
4187 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
4188 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
4192 VectorClear( endpos );
4194 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4195 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4196 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4199 void R_Shadow_UpdateWorldLightSelection(void)
4201 if (r_editlights.integer)
4203 R_Shadow_SetCursorLocationForView();
4204 R_Shadow_SelectLightInView();
4207 R_Shadow_SelectLight(NULL);
4210 void R_Shadow_EditLights_Clear_f(void)
4212 R_Shadow_ClearWorldLights();
4215 void R_Shadow_EditLights_Reload_f(void)
4219 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
4220 R_Shadow_ClearWorldLights();
4221 R_Shadow_LoadWorldLights();
4222 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4224 R_Shadow_LoadLightsFile();
4225 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4226 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4230 void R_Shadow_EditLights_Save_f(void)
4234 R_Shadow_SaveWorldLights();
4237 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
4239 R_Shadow_ClearWorldLights();
4240 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4243 void R_Shadow_EditLights_ImportLightsFile_f(void)
4245 R_Shadow_ClearWorldLights();
4246 R_Shadow_LoadLightsFile();
4249 void R_Shadow_EditLights_Spawn_f(void)
4252 if (!r_editlights.integer)
4254 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4257 if (Cmd_Argc() != 1)
4259 Con_Print("r_editlights_spawn does not take parameters\n");
4262 color[0] = color[1] = color[2] = 1;
4263 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4266 void R_Shadow_EditLights_Edit_f(void)
4268 vec3_t origin, angles, color;
4269 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
4270 int style, shadows, flags, normalmode, realtimemode;
4271 char cubemapname[MAX_INPUTLINE];
4272 if (!r_editlights.integer)
4274 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4277 if (!r_shadow_selectedlight)
4279 Con_Print("No selected light.\n");
4282 VectorCopy(r_shadow_selectedlight->origin, origin);
4283 VectorCopy(r_shadow_selectedlight->angles, angles);
4284 VectorCopy(r_shadow_selectedlight->color, color);
4285 radius = r_shadow_selectedlight->radius;
4286 style = r_shadow_selectedlight->style;
4287 if (r_shadow_selectedlight->cubemapname)
4288 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
4291 shadows = r_shadow_selectedlight->shadow;
4292 corona = r_shadow_selectedlight->corona;
4293 coronasizescale = r_shadow_selectedlight->coronasizescale;
4294 ambientscale = r_shadow_selectedlight->ambientscale;
4295 diffusescale = r_shadow_selectedlight->diffusescale;
4296 specularscale = r_shadow_selectedlight->specularscale;
4297 flags = r_shadow_selectedlight->flags;
4298 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
4299 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
4300 if (!strcmp(Cmd_Argv(1), "origin"))
4302 if (Cmd_Argc() != 5)
4304 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4307 origin[0] = atof(Cmd_Argv(2));
4308 origin[1] = atof(Cmd_Argv(3));
4309 origin[2] = atof(Cmd_Argv(4));
4311 else if (!strcmp(Cmd_Argv(1), "originx"))
4313 if (Cmd_Argc() != 3)
4315 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4318 origin[0] = atof(Cmd_Argv(2));
4320 else if (!strcmp(Cmd_Argv(1), "originy"))
4322 if (Cmd_Argc() != 3)
4324 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4327 origin[1] = atof(Cmd_Argv(2));
4329 else if (!strcmp(Cmd_Argv(1), "originz"))
4331 if (Cmd_Argc() != 3)
4333 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4336 origin[2] = atof(Cmd_Argv(2));
4338 else if (!strcmp(Cmd_Argv(1), "move"))
4340 if (Cmd_Argc() != 5)
4342 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4345 origin[0] += atof(Cmd_Argv(2));
4346 origin[1] += atof(Cmd_Argv(3));
4347 origin[2] += atof(Cmd_Argv(4));
4349 else if (!strcmp(Cmd_Argv(1), "movex"))
4351 if (Cmd_Argc() != 3)
4353 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4356 origin[0] += atof(Cmd_Argv(2));
4358 else if (!strcmp(Cmd_Argv(1), "movey"))
4360 if (Cmd_Argc() != 3)
4362 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4365 origin[1] += atof(Cmd_Argv(2));
4367 else if (!strcmp(Cmd_Argv(1), "movez"))
4369 if (Cmd_Argc() != 3)
4371 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4374 origin[2] += atof(Cmd_Argv(2));
4376 else if (!strcmp(Cmd_Argv(1), "angles"))
4378 if (Cmd_Argc() != 5)
4380 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4383 angles[0] = atof(Cmd_Argv(2));
4384 angles[1] = atof(Cmd_Argv(3));
4385 angles[2] = atof(Cmd_Argv(4));
4387 else if (!strcmp(Cmd_Argv(1), "anglesx"))
4389 if (Cmd_Argc() != 3)
4391 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4394 angles[0] = atof(Cmd_Argv(2));
4396 else if (!strcmp(Cmd_Argv(1), "anglesy"))
4398 if (Cmd_Argc() != 3)
4400 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4403 angles[1] = atof(Cmd_Argv(2));
4405 else if (!strcmp(Cmd_Argv(1), "anglesz"))
4407 if (Cmd_Argc() != 3)
4409 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4412 angles[2] = atof(Cmd_Argv(2));
4414 else if (!strcmp(Cmd_Argv(1), "color"))
4416 if (Cmd_Argc() != 5)
4418 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
4421 color[0] = atof(Cmd_Argv(2));
4422 color[1] = atof(Cmd_Argv(3));
4423 color[2] = atof(Cmd_Argv(4));
4425 else if (!strcmp(Cmd_Argv(1), "radius"))
4427 if (Cmd_Argc() != 3)
4429 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4432 radius = atof(Cmd_Argv(2));
4434 else if (!strcmp(Cmd_Argv(1), "colorscale"))
4436 if (Cmd_Argc() == 3)
4438 double scale = atof(Cmd_Argv(2));
4445 if (Cmd_Argc() != 5)
4447 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
4450 color[0] *= atof(Cmd_Argv(2));
4451 color[1] *= atof(Cmd_Argv(3));
4452 color[2] *= atof(Cmd_Argv(4));
4455 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
4457 if (Cmd_Argc() != 3)
4459 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4462 radius *= atof(Cmd_Argv(2));
4464 else if (!strcmp(Cmd_Argv(1), "style"))
4466 if (Cmd_Argc() != 3)
4468 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4471 style = atoi(Cmd_Argv(2));
4473 else if (!strcmp(Cmd_Argv(1), "cubemap"))
4477 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4480 if (Cmd_Argc() == 3)
4481 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
4485 else if (!strcmp(Cmd_Argv(1), "shadows"))
4487 if (Cmd_Argc() != 3)
4489 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4492 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4494 else if (!strcmp(Cmd_Argv(1), "corona"))
4496 if (Cmd_Argc() != 3)
4498 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4501 corona = atof(Cmd_Argv(2));
4503 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4505 if (Cmd_Argc() != 3)
4507 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4510 coronasizescale = atof(Cmd_Argv(2));
4512 else if (!strcmp(Cmd_Argv(1), "ambient"))
4514 if (Cmd_Argc() != 3)
4516 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4519 ambientscale = atof(Cmd_Argv(2));
4521 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4523 if (Cmd_Argc() != 3)
4525 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4528 diffusescale = atof(Cmd_Argv(2));
4530 else if (!strcmp(Cmd_Argv(1), "specular"))
4532 if (Cmd_Argc() != 3)
4534 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4537 specularscale = atof(Cmd_Argv(2));
4539 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4541 if (Cmd_Argc() != 3)
4543 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4546 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4548 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4550 if (Cmd_Argc() != 3)
4552 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4555 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4559 Con_Print("usage: r_editlights_edit [property] [value]\n");
4560 Con_Print("Selected light's properties:\n");
4561 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4562 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4563 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4564 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4565 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4566 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4567 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4568 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4569 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4570 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4571 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4572 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4573 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4574 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4577 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4578 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4581 void R_Shadow_EditLights_EditAll_f(void)
4587 if (!r_editlights.integer)
4589 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4593 // EditLights doesn't seem to have a "remove" command or something so:
4594 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4595 for (lightindex = 0;lightindex < range;lightindex++)
4597 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4600 R_Shadow_SelectLight(light);
4601 R_Shadow_EditLights_Edit_f();
4605 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4607 int lightnumber, lightcount;
4608 size_t lightindex, range;
4612 if (!r_editlights.integer)
4614 x = vid_conwidth.value - 240;
4616 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
4619 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4620 for (lightindex = 0;lightindex < range;lightindex++)
4622 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4625 if (light == r_shadow_selectedlight)
4626 lightnumber = lightindex;
4629 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;
4630 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;
4632 if (r_shadow_selectedlight == NULL)
4634 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;
4635 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;
4636 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;
4637 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;
4638 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;
4639 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;
4640 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;
4641 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;
4642 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;
4643 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;
4644 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;
4645 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;
4646 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;
4647 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;
4648 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;
4651 void R_Shadow_EditLights_ToggleShadow_f(void)
4653 if (!r_editlights.integer)
4655 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4658 if (!r_shadow_selectedlight)
4660 Con_Print("No selected light.\n");
4663 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);
4666 void R_Shadow_EditLights_ToggleCorona_f(void)
4668 if (!r_editlights.integer)
4670 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4673 if (!r_shadow_selectedlight)
4675 Con_Print("No selected light.\n");
4678 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);
4681 void R_Shadow_EditLights_Remove_f(void)
4683 if (!r_editlights.integer)
4685 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4688 if (!r_shadow_selectedlight)
4690 Con_Print("No selected light.\n");
4693 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4694 r_shadow_selectedlight = NULL;
4697 void R_Shadow_EditLights_Help_f(void)
4700 "Documentation on r_editlights system:\n"
4702 "r_editlights : enable/disable editing mode\n"
4703 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4704 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4705 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4706 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4707 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4709 "r_editlights_help : this help\n"
4710 "r_editlights_clear : remove all lights\n"
4711 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4712 "r_editlights_save : save to .rtlights file\n"
4713 "r_editlights_spawn : create a light with default settings\n"
4714 "r_editlights_edit command : edit selected light - more documentation below\n"
4715 "r_editlights_remove : remove selected light\n"
4716 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4717 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4718 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4720 "origin x y z : set light location\n"
4721 "originx x: set x component of light location\n"
4722 "originy y: set y component of light location\n"
4723 "originz z: set z component of light location\n"
4724 "move x y z : adjust light location\n"
4725 "movex x: adjust x component of light location\n"
4726 "movey y: adjust y component of light location\n"
4727 "movez z: adjust z component of light location\n"
4728 "angles x y z : set light angles\n"
4729 "anglesx x: set x component of light angles\n"
4730 "anglesy y: set y component of light angles\n"
4731 "anglesz z: set z component of light angles\n"
4732 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4733 "radius radius : set radius (size) of light\n"
4734 "colorscale grey : multiply color of light (1 does nothing)\n"
4735 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4736 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4737 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4738 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4739 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4740 "shadows 1/0 : turn on/off shadows\n"
4741 "corona n : set corona intensity\n"
4742 "coronasize n : set corona size (0-1)\n"
4743 "ambient n : set ambient intensity (0-1)\n"
4744 "diffuse n : set diffuse intensity (0-1)\n"
4745 "specular n : set specular intensity (0-1)\n"
4746 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4747 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4748 "<nothing> : print light properties to console\n"
4752 void R_Shadow_EditLights_CopyInfo_f(void)
4754 if (!r_editlights.integer)
4756 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4759 if (!r_shadow_selectedlight)
4761 Con_Print("No selected light.\n");
4764 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4765 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4766 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4767 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4768 if (r_shadow_selectedlight->cubemapname)
4769 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
4771 r_shadow_bufferlight.cubemapname[0] = 0;
4772 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4773 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4774 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4775 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4776 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4777 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4778 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4781 void R_Shadow_EditLights_PasteInfo_f(void)
4783 if (!r_editlights.integer)
4785 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4788 if (!r_shadow_selectedlight)
4790 Con_Print("No selected light.\n");
4793 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);
4796 void R_Shadow_EditLights_Init(void)
4798 Cvar_RegisterVariable(&r_editlights);
4799 Cvar_RegisterVariable(&r_editlights_cursordistance);
4800 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4801 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4802 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4803 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4804 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
4805 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
4806 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)");
4807 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
4808 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
4809 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
4810 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)");
4811 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
4812 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
4813 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
4814 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
4815 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
4816 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
4817 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)");
4823 =============================================================================
4827 =============================================================================
4830 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
4832 VectorClear(diffusecolor);
4833 VectorClear(diffusenormal);
4835 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
4837 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
4838 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
4841 VectorSet(ambientcolor, 1, 1, 1);
4848 for (i = 0;i < r_refdef.scene.numlights;i++)
4850 light = &r_refdef.scene.lights[i];
4851 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
4852 f = 1 - VectorLength2(v);
4853 if (f > 0 && CL_Move(p, vec3_origin, vec3_origin, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
4854 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);