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_ZPASS_STENCIL,
149 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
150 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
151 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
152 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
153 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
154 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
155 R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN,
156 R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN,
157 R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN,
158 R_SHADOW_RENDERMODE_LIGHT_GLSL,
159 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
160 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
161 R_SHADOW_RENDERMODE_SHADOWMAP2D,
162 R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE,
163 R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE,
165 r_shadow_rendermode_t;
167 typedef enum r_shadow_shadowmode_e
169 R_SHADOW_SHADOWMODE_STENCIL,
170 R_SHADOW_SHADOWMODE_SHADOWMAP2D,
171 R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE,
172 R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE
174 r_shadow_shadowmode_t;
176 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
177 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
178 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
180 qboolean r_shadow_usingshadowmaprect;
181 qboolean r_shadow_usingshadowmap2d;
182 qboolean r_shadow_usingshadowmapcube;
183 qboolean r_shadow_usingshadowmaportho;
184 int r_shadow_shadowmapside;
185 float r_shadow_shadowmap_texturescale[2];
186 float r_shadow_shadowmap_parameters[4];
188 int r_shadow_drawbuffer;
189 int r_shadow_readbuffer;
191 int r_shadow_cullface_front, r_shadow_cullface_back;
192 GLuint r_shadow_fborectangle;
193 GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
194 GLuint r_shadow_fbo2d;
195 r_shadow_shadowmode_t r_shadow_shadowmode;
196 int r_shadow_shadowmapfilterquality;
197 int r_shadow_shadowmaptexturetype;
198 int r_shadow_shadowmapdepthbits;
199 int r_shadow_shadowmapmaxsize;
200 qboolean r_shadow_shadowmapvsdct;
201 qboolean r_shadow_shadowmapsampler;
202 int r_shadow_shadowmappcf;
203 int r_shadow_shadowmapborder;
204 matrix4x4_t r_shadow_shadowmapmatrix;
205 int r_shadow_lightscissor[4];
206 qboolean r_shadow_usingdeferredprepass;
208 int maxshadowtriangles;
211 int maxshadowvertices;
212 float *shadowvertex3f;
222 unsigned char *shadowsides;
223 int *shadowsideslist;
230 int r_shadow_buffer_numleafpvsbytes;
231 unsigned char *r_shadow_buffer_visitingleafpvs;
232 unsigned char *r_shadow_buffer_leafpvs;
233 int *r_shadow_buffer_leaflist;
235 int r_shadow_buffer_numsurfacepvsbytes;
236 unsigned char *r_shadow_buffer_surfacepvs;
237 int *r_shadow_buffer_surfacelist;
238 unsigned char *r_shadow_buffer_surfacesides;
240 int r_shadow_buffer_numshadowtrispvsbytes;
241 unsigned char *r_shadow_buffer_shadowtrispvs;
242 int r_shadow_buffer_numlighttrispvsbytes;
243 unsigned char *r_shadow_buffer_lighttrispvs;
245 rtexturepool_t *r_shadow_texturepool;
246 rtexture_t *r_shadow_attenuationgradienttexture;
247 rtexture_t *r_shadow_attenuation2dtexture;
248 rtexture_t *r_shadow_attenuation3dtexture;
249 skinframe_t *r_shadow_lightcorona;
250 rtexture_t *r_shadow_shadowmaprectangletexture;
251 rtexture_t *r_shadow_shadowmap2dtexture;
252 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
253 rtexture_t *r_shadow_shadowmapvsdcttexture;
254 int r_shadow_shadowmapsize; // changes for each light based on distance
255 int r_shadow_shadowmaplod; // changes for each light based on distance
257 GLuint r_shadow_prepassgeometryfbo;
258 GLuint r_shadow_prepasslightingfbo;
259 int r_shadow_prepass_width;
260 int r_shadow_prepass_height;
261 rtexture_t *r_shadow_prepassgeometrydepthtexture;
262 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
263 rtexture_t *r_shadow_prepasslightingdiffusetexture;
264 rtexture_t *r_shadow_prepasslightingspeculartexture;
266 // lights are reloaded when this changes
267 char r_shadow_mapname[MAX_QPATH];
269 // used only for light filters (cubemaps)
270 rtexturepool_t *r_shadow_filters_texturepool;
272 static const GLenum r_shadow_prepasslightingdrawbuffers[2] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
274 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"};
275 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"};
276 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
277 cvar_t r_shadow_deferred = {CVAR_SAVE, "r_shadow_deferred", "0", "uses image-based lighting instead of geometry-based lighting, the method used renders a depth image and a normalmap image, renders lights into separate diffuse and specular images, and then combines this into the normal rendering, requires r_shadow_shadowmapping"};
278 cvar_t r_shadow_deferred_8bitrange = {CVAR_SAVE, "r_shadow_deferred_8bitrange", "2", "dynamic range of image-based lighting when using 32bit color (does not apply to fp)"};
279 //cvar_t r_shadow_deferred_fp = {CVAR_SAVE, "r_shadow_deferred_fp", "0", "use 16bit (1) or 32bit (2) floating point for accumulation of image-based lighting"};
280 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
281 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)"};
282 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"};
283 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
284 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
285 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
286 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
287 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
288 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
289 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
290 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
291 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
292 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)"};
293 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
294 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
295 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
296 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
297 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)"};
298 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"};
299 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
300 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
301 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"};
302 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation (slower than compileportalculling but more exact)"};
303 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "0", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
304 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)"};
305 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "0", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"};
306 cvar_t r_shadow_shadowmapping_texturetype = {CVAR_SAVE, "r_shadow_shadowmapping_texturetype", "-1", "shadowmap texture types: -1 = auto-select, 0 = 2D, 1 = rectangle, 2 = cubemap"};
307 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
308 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
309 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
310 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
311 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
312 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
313 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
314 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
315 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
316 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
317 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
318 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
319 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
320 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
321 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)"};
322 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect OpenGL 2.0 render path)"};
323 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
324 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"};
325 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
326 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
327 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
328 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
329 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
330 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
331 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
332 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
333 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
334 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
336 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
337 #define ATTENTABLESIZE 256
338 // 1D gradient, 2D circle and 3D sphere attenuation textures
339 #define ATTEN1DSIZE 32
340 #define ATTEN2DSIZE 64
341 #define ATTEN3DSIZE 32
343 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
344 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
345 static float r_shadow_attentable[ATTENTABLESIZE+1];
347 rtlight_t *r_shadow_compilingrtlight;
348 static memexpandablearray_t r_shadow_worldlightsarray;
349 dlight_t *r_shadow_selectedlight;
350 dlight_t r_shadow_bufferlight;
351 vec3_t r_editlights_cursorlocation;
353 extern int con_vislines;
355 void R_Shadow_UncompileWorldLights(void);
356 void R_Shadow_ClearWorldLights(void);
357 void R_Shadow_SaveWorldLights(void);
358 void R_Shadow_LoadWorldLights(void);
359 void R_Shadow_LoadLightsFile(void);
360 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
361 void R_Shadow_EditLights_Reload_f(void);
362 void R_Shadow_ValidateCvars(void);
363 static void R_Shadow_MakeTextures(void);
365 #define EDLIGHTSPRSIZE 8
366 skinframe_t *r_editlights_sprcursor;
367 skinframe_t *r_editlights_sprlight;
368 skinframe_t *r_editlights_sprnoshadowlight;
369 skinframe_t *r_editlights_sprcubemaplight;
370 skinframe_t *r_editlights_sprcubemapnoshadowlight;
371 skinframe_t *r_editlights_sprselection;
373 void R_Shadow_SetShadowMode(void)
375 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
376 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
377 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
378 r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
379 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
380 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
381 r_shadow_shadowmaplod = -1;
382 r_shadow_shadowmapsize = 0;
383 r_shadow_shadowmapsampler = false;
384 r_shadow_shadowmappcf = 0;
385 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
386 switch(vid.renderpath)
388 case RENDERPATH_GL20:
389 case RENDERPATH_CGGL:
390 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
392 if(r_shadow_shadowmapfilterquality < 0)
394 if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
395 r_shadow_shadowmappcf = 1;
396 else if(strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD"))
398 r_shadow_shadowmapsampler = vid.support.arb_shadow;
399 r_shadow_shadowmappcf = 1;
401 else if(strstr(gl_vendor, "ATI"))
402 r_shadow_shadowmappcf = 1;
404 r_shadow_shadowmapsampler = vid.support.arb_shadow;
408 switch (r_shadow_shadowmapfilterquality)
411 r_shadow_shadowmapsampler = vid.support.arb_shadow;
414 r_shadow_shadowmapsampler = vid.support.arb_shadow;
415 r_shadow_shadowmappcf = 1;
418 r_shadow_shadowmappcf = 1;
421 r_shadow_shadowmappcf = 2;
425 switch (r_shadow_shadowmaptexturetype)
428 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
431 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
434 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE;
437 if((vid.support.amd_texture_texture4 || vid.support.arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
438 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
439 else if(vid.support.arb_texture_rectangle)
440 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
442 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
447 case RENDERPATH_GL13:
449 case RENDERPATH_GL11:
454 qboolean R_Shadow_ShadowMappingEnabled(void)
456 switch (r_shadow_shadowmode)
458 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
459 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
460 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
467 void R_Shadow_FreeShadowMaps(void)
471 R_Shadow_SetShadowMode();
473 if (!vid.support.ext_framebuffer_object || !vid.support.arb_fragment_shader)
478 if (r_shadow_fborectangle)
479 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
480 r_shadow_fborectangle = 0;
483 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
485 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
486 if (r_shadow_fbocubeside[i])
487 qglDeleteFramebuffersEXT(1, &r_shadow_fbocubeside[i]);CHECKGLERROR
488 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
490 if (r_shadow_shadowmaprectangletexture)
491 R_FreeTexture(r_shadow_shadowmaprectangletexture);
492 r_shadow_shadowmaprectangletexture = NULL;
494 if (r_shadow_shadowmap2dtexture)
495 R_FreeTexture(r_shadow_shadowmap2dtexture);
496 r_shadow_shadowmap2dtexture = NULL;
498 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
499 if (r_shadow_shadowmapcubetexture[i])
500 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
501 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
503 if (r_shadow_shadowmapvsdcttexture)
504 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
505 r_shadow_shadowmapvsdcttexture = NULL;
509 r_shadow_usingshadowmaportho = false;
512 void r_shadow_start(void)
514 // allocate vertex processing arrays
515 r_shadow_attenuationgradienttexture = NULL;
516 r_shadow_attenuation2dtexture = NULL;
517 r_shadow_attenuation3dtexture = NULL;
518 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
519 r_shadow_shadowmaprectangletexture = NULL;
520 r_shadow_shadowmap2dtexture = NULL;
521 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
522 r_shadow_shadowmapvsdcttexture = NULL;
523 r_shadow_shadowmapmaxsize = 0;
524 r_shadow_shadowmapsize = 0;
525 r_shadow_shadowmaplod = 0;
526 r_shadow_shadowmapfilterquality = -1;
527 r_shadow_shadowmaptexturetype = -1;
528 r_shadow_shadowmapdepthbits = 0;
529 r_shadow_shadowmapvsdct = false;
530 r_shadow_shadowmapsampler = false;
531 r_shadow_shadowmappcf = 0;
532 r_shadow_fborectangle = 0;
534 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
536 R_Shadow_FreeShadowMaps();
538 r_shadow_texturepool = NULL;
539 r_shadow_filters_texturepool = NULL;
540 R_Shadow_ValidateCvars();
541 R_Shadow_MakeTextures();
542 maxshadowtriangles = 0;
543 shadowelements = NULL;
544 maxshadowvertices = 0;
545 shadowvertex3f = NULL;
553 shadowmarklist = NULL;
558 shadowsideslist = NULL;
559 r_shadow_buffer_numleafpvsbytes = 0;
560 r_shadow_buffer_visitingleafpvs = NULL;
561 r_shadow_buffer_leafpvs = NULL;
562 r_shadow_buffer_leaflist = NULL;
563 r_shadow_buffer_numsurfacepvsbytes = 0;
564 r_shadow_buffer_surfacepvs = NULL;
565 r_shadow_buffer_surfacelist = NULL;
566 r_shadow_buffer_surfacesides = NULL;
567 r_shadow_buffer_numshadowtrispvsbytes = 0;
568 r_shadow_buffer_shadowtrispvs = NULL;
569 r_shadow_buffer_numlighttrispvsbytes = 0;
570 r_shadow_buffer_lighttrispvs = NULL;
572 r_shadow_usingdeferredprepass = false;
573 r_shadow_prepass_width = r_shadow_prepass_height = 0;
576 static void R_Shadow_FreeDeferred(void);
577 void r_shadow_shutdown(void)
580 R_Shadow_UncompileWorldLights();
582 R_Shadow_FreeShadowMaps();
584 r_shadow_usingdeferredprepass = false;
585 if (r_shadow_prepass_width)
586 R_Shadow_FreeDeferred();
587 r_shadow_prepass_width = r_shadow_prepass_height = 0;
590 r_shadow_attenuationgradienttexture = NULL;
591 r_shadow_attenuation2dtexture = NULL;
592 r_shadow_attenuation3dtexture = NULL;
593 R_FreeTexturePool(&r_shadow_texturepool);
594 R_FreeTexturePool(&r_shadow_filters_texturepool);
595 maxshadowtriangles = 0;
597 Mem_Free(shadowelements);
598 shadowelements = NULL;
600 Mem_Free(shadowvertex3f);
601 shadowvertex3f = NULL;
604 Mem_Free(vertexupdate);
607 Mem_Free(vertexremap);
613 Mem_Free(shadowmark);
616 Mem_Free(shadowmarklist);
617 shadowmarklist = NULL;
622 Mem_Free(shadowsides);
625 Mem_Free(shadowsideslist);
626 shadowsideslist = NULL;
627 r_shadow_buffer_numleafpvsbytes = 0;
628 if (r_shadow_buffer_visitingleafpvs)
629 Mem_Free(r_shadow_buffer_visitingleafpvs);
630 r_shadow_buffer_visitingleafpvs = NULL;
631 if (r_shadow_buffer_leafpvs)
632 Mem_Free(r_shadow_buffer_leafpvs);
633 r_shadow_buffer_leafpvs = NULL;
634 if (r_shadow_buffer_leaflist)
635 Mem_Free(r_shadow_buffer_leaflist);
636 r_shadow_buffer_leaflist = NULL;
637 r_shadow_buffer_numsurfacepvsbytes = 0;
638 if (r_shadow_buffer_surfacepvs)
639 Mem_Free(r_shadow_buffer_surfacepvs);
640 r_shadow_buffer_surfacepvs = NULL;
641 if (r_shadow_buffer_surfacelist)
642 Mem_Free(r_shadow_buffer_surfacelist);
643 r_shadow_buffer_surfacelist = NULL;
644 if (r_shadow_buffer_surfacesides)
645 Mem_Free(r_shadow_buffer_surfacesides);
646 r_shadow_buffer_surfacesides = NULL;
647 r_shadow_buffer_numshadowtrispvsbytes = 0;
648 if (r_shadow_buffer_shadowtrispvs)
649 Mem_Free(r_shadow_buffer_shadowtrispvs);
650 r_shadow_buffer_numlighttrispvsbytes = 0;
651 if (r_shadow_buffer_lighttrispvs)
652 Mem_Free(r_shadow_buffer_lighttrispvs);
655 void r_shadow_newmap(void)
657 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
658 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
659 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
660 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
661 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
662 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
663 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
664 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
665 R_Shadow_EditLights_Reload_f();
668 void R_Shadow_Init(void)
670 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
671 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
672 Cvar_RegisterVariable(&r_shadow_usenormalmap);
673 Cvar_RegisterVariable(&r_shadow_debuglight);
674 Cvar_RegisterVariable(&r_shadow_deferred);
675 Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
676 // Cvar_RegisterVariable(&r_shadow_deferred_fp);
677 Cvar_RegisterVariable(&r_shadow_gloss);
678 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
679 Cvar_RegisterVariable(&r_shadow_glossintensity);
680 Cvar_RegisterVariable(&r_shadow_glossexponent);
681 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
682 Cvar_RegisterVariable(&r_shadow_glossexact);
683 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
684 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
685 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
686 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
687 Cvar_RegisterVariable(&r_shadow_projectdistance);
688 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
689 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
690 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
691 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
692 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
693 Cvar_RegisterVariable(&r_shadow_realtime_world);
694 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
695 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
696 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
697 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
698 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
699 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
700 Cvar_RegisterVariable(&r_shadow_scissor);
701 Cvar_RegisterVariable(&r_shadow_shadowmapping);
702 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
703 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
704 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
705 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
706 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
707 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
708 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
709 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
710 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
711 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
712 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
713 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
714 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
715 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
716 Cvar_RegisterVariable(&r_shadow_polygonfactor);
717 Cvar_RegisterVariable(&r_shadow_polygonoffset);
718 Cvar_RegisterVariable(&r_shadow_texture3d);
719 Cvar_RegisterVariable(&r_coronas);
720 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
721 Cvar_RegisterVariable(&r_coronas_occlusionquery);
722 Cvar_RegisterVariable(&gl_flashblend);
723 Cvar_RegisterVariable(&gl_ext_separatestencil);
724 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
725 if (gamemode == GAME_TENEBRAE)
727 Cvar_SetValue("r_shadow_gloss", 2);
728 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
730 R_Shadow_EditLights_Init();
731 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
732 maxshadowtriangles = 0;
733 shadowelements = NULL;
734 maxshadowvertices = 0;
735 shadowvertex3f = NULL;
743 shadowmarklist = NULL;
748 shadowsideslist = NULL;
749 r_shadow_buffer_numleafpvsbytes = 0;
750 r_shadow_buffer_visitingleafpvs = NULL;
751 r_shadow_buffer_leafpvs = NULL;
752 r_shadow_buffer_leaflist = NULL;
753 r_shadow_buffer_numsurfacepvsbytes = 0;
754 r_shadow_buffer_surfacepvs = NULL;
755 r_shadow_buffer_surfacelist = NULL;
756 r_shadow_buffer_surfacesides = NULL;
757 r_shadow_buffer_shadowtrispvs = NULL;
758 r_shadow_buffer_lighttrispvs = NULL;
759 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
762 matrix4x4_t matrix_attenuationxyz =
765 {0.5, 0.0, 0.0, 0.5},
766 {0.0, 0.5, 0.0, 0.5},
767 {0.0, 0.0, 0.5, 0.5},
772 matrix4x4_t matrix_attenuationz =
775 {0.0, 0.0, 0.5, 0.5},
776 {0.0, 0.0, 0.0, 0.5},
777 {0.0, 0.0, 0.0, 0.5},
782 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
784 numvertices = ((numvertices + 255) & ~255) * vertscale;
785 numtriangles = ((numtriangles + 255) & ~255) * triscale;
786 // make sure shadowelements is big enough for this volume
787 if (maxshadowtriangles < numtriangles)
789 maxshadowtriangles = numtriangles;
791 Mem_Free(shadowelements);
792 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
794 // make sure shadowvertex3f is big enough for this volume
795 if (maxshadowvertices < numvertices)
797 maxshadowvertices = numvertices;
799 Mem_Free(shadowvertex3f);
800 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
804 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
806 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
807 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
808 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
809 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
810 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
812 if (r_shadow_buffer_visitingleafpvs)
813 Mem_Free(r_shadow_buffer_visitingleafpvs);
814 if (r_shadow_buffer_leafpvs)
815 Mem_Free(r_shadow_buffer_leafpvs);
816 if (r_shadow_buffer_leaflist)
817 Mem_Free(r_shadow_buffer_leaflist);
818 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
819 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
820 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
821 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
823 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
825 if (r_shadow_buffer_surfacepvs)
826 Mem_Free(r_shadow_buffer_surfacepvs);
827 if (r_shadow_buffer_surfacelist)
828 Mem_Free(r_shadow_buffer_surfacelist);
829 if (r_shadow_buffer_surfacesides)
830 Mem_Free(r_shadow_buffer_surfacesides);
831 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
832 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
833 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
834 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
836 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
838 if (r_shadow_buffer_shadowtrispvs)
839 Mem_Free(r_shadow_buffer_shadowtrispvs);
840 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
841 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
843 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
845 if (r_shadow_buffer_lighttrispvs)
846 Mem_Free(r_shadow_buffer_lighttrispvs);
847 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
848 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
852 void R_Shadow_PrepareShadowMark(int numtris)
854 // make sure shadowmark is big enough for this volume
855 if (maxshadowmark < numtris)
857 maxshadowmark = numtris;
859 Mem_Free(shadowmark);
861 Mem_Free(shadowmarklist);
862 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
863 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
867 // if shadowmarkcount wrapped we clear the array and adjust accordingly
868 if (shadowmarkcount == 0)
871 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
876 void R_Shadow_PrepareShadowSides(int numtris)
878 if (maxshadowsides < numtris)
880 maxshadowsides = numtris;
882 Mem_Free(shadowsides);
884 Mem_Free(shadowsideslist);
885 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
886 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
891 static int R_Shadow_ConstructShadowVolume_ZFail(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)
894 int outtriangles = 0, outvertices = 0;
897 float ratio, direction[3], projectvector[3];
899 if (projectdirection)
900 VectorScale(projectdirection, projectdistance, projectvector);
902 VectorClear(projectvector);
904 // create the vertices
905 if (projectdirection)
907 for (i = 0;i < numshadowmarktris;i++)
909 element = inelement3i + shadowmarktris[i] * 3;
910 for (j = 0;j < 3;j++)
912 if (vertexupdate[element[j]] != vertexupdatenum)
914 vertexupdate[element[j]] = vertexupdatenum;
915 vertexremap[element[j]] = outvertices;
916 vertex = invertex3f + element[j] * 3;
917 // project one copy of the vertex according to projectvector
918 VectorCopy(vertex, outvertex3f);
919 VectorAdd(vertex, projectvector, (outvertex3f + 3));
928 for (i = 0;i < numshadowmarktris;i++)
930 element = inelement3i + shadowmarktris[i] * 3;
931 for (j = 0;j < 3;j++)
933 if (vertexupdate[element[j]] != vertexupdatenum)
935 vertexupdate[element[j]] = vertexupdatenum;
936 vertexremap[element[j]] = outvertices;
937 vertex = invertex3f + element[j] * 3;
938 // project one copy of the vertex to the sphere radius of the light
939 // (FIXME: would projecting it to the light box be better?)
940 VectorSubtract(vertex, projectorigin, direction);
941 ratio = projectdistance / VectorLength(direction);
942 VectorCopy(vertex, outvertex3f);
943 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
951 if (r_shadow_frontsidecasting.integer)
953 for (i = 0;i < numshadowmarktris;i++)
955 int remappedelement[3];
957 const int *neighbortriangle;
959 markindex = shadowmarktris[i] * 3;
960 element = inelement3i + markindex;
961 neighbortriangle = inneighbor3i + markindex;
962 // output the front and back triangles
963 outelement3i[0] = vertexremap[element[0]];
964 outelement3i[1] = vertexremap[element[1]];
965 outelement3i[2] = vertexremap[element[2]];
966 outelement3i[3] = vertexremap[element[2]] + 1;
967 outelement3i[4] = vertexremap[element[1]] + 1;
968 outelement3i[5] = vertexremap[element[0]] + 1;
972 // output the sides (facing outward from this triangle)
973 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
975 remappedelement[0] = vertexremap[element[0]];
976 remappedelement[1] = vertexremap[element[1]];
977 outelement3i[0] = remappedelement[1];
978 outelement3i[1] = remappedelement[0];
979 outelement3i[2] = remappedelement[0] + 1;
980 outelement3i[3] = remappedelement[1];
981 outelement3i[4] = remappedelement[0] + 1;
982 outelement3i[5] = remappedelement[1] + 1;
987 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
989 remappedelement[1] = vertexremap[element[1]];
990 remappedelement[2] = vertexremap[element[2]];
991 outelement3i[0] = remappedelement[2];
992 outelement3i[1] = remappedelement[1];
993 outelement3i[2] = remappedelement[1] + 1;
994 outelement3i[3] = remappedelement[2];
995 outelement3i[4] = remappedelement[1] + 1;
996 outelement3i[5] = remappedelement[2] + 1;
1001 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1003 remappedelement[0] = vertexremap[element[0]];
1004 remappedelement[2] = vertexremap[element[2]];
1005 outelement3i[0] = remappedelement[0];
1006 outelement3i[1] = remappedelement[2];
1007 outelement3i[2] = remappedelement[2] + 1;
1008 outelement3i[3] = remappedelement[0];
1009 outelement3i[4] = remappedelement[2] + 1;
1010 outelement3i[5] = remappedelement[0] + 1;
1019 for (i = 0;i < numshadowmarktris;i++)
1021 int remappedelement[3];
1023 const int *neighbortriangle;
1025 markindex = shadowmarktris[i] * 3;
1026 element = inelement3i + markindex;
1027 neighbortriangle = inneighbor3i + markindex;
1028 // output the front and back triangles
1029 outelement3i[0] = vertexremap[element[2]];
1030 outelement3i[1] = vertexremap[element[1]];
1031 outelement3i[2] = vertexremap[element[0]];
1032 outelement3i[3] = vertexremap[element[0]] + 1;
1033 outelement3i[4] = vertexremap[element[1]] + 1;
1034 outelement3i[5] = vertexremap[element[2]] + 1;
1038 // output the sides (facing outward from this triangle)
1039 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1041 remappedelement[0] = vertexremap[element[0]];
1042 remappedelement[1] = vertexremap[element[1]];
1043 outelement3i[0] = remappedelement[0];
1044 outelement3i[1] = remappedelement[1];
1045 outelement3i[2] = remappedelement[1] + 1;
1046 outelement3i[3] = remappedelement[0];
1047 outelement3i[4] = remappedelement[1] + 1;
1048 outelement3i[5] = remappedelement[0] + 1;
1053 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1055 remappedelement[1] = vertexremap[element[1]];
1056 remappedelement[2] = vertexremap[element[2]];
1057 outelement3i[0] = remappedelement[1];
1058 outelement3i[1] = remappedelement[2];
1059 outelement3i[2] = remappedelement[2] + 1;
1060 outelement3i[3] = remappedelement[1];
1061 outelement3i[4] = remappedelement[2] + 1;
1062 outelement3i[5] = remappedelement[1] + 1;
1067 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1069 remappedelement[0] = vertexremap[element[0]];
1070 remappedelement[2] = vertexremap[element[2]];
1071 outelement3i[0] = remappedelement[2];
1072 outelement3i[1] = remappedelement[0];
1073 outelement3i[2] = remappedelement[0] + 1;
1074 outelement3i[3] = remappedelement[2];
1075 outelement3i[4] = remappedelement[0] + 1;
1076 outelement3i[5] = remappedelement[2] + 1;
1084 *outnumvertices = outvertices;
1085 return outtriangles;
1088 static int R_Shadow_ConstructShadowVolume_ZPass(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)
1091 int outtriangles = 0, outvertices = 0;
1093 const float *vertex;
1094 float ratio, direction[3], projectvector[3];
1097 if (projectdirection)
1098 VectorScale(projectdirection, projectdistance, projectvector);
1100 VectorClear(projectvector);
1102 for (i = 0;i < numshadowmarktris;i++)
1104 int remappedelement[3];
1106 const int *neighbortriangle;
1108 markindex = shadowmarktris[i] * 3;
1109 neighbortriangle = inneighbor3i + markindex;
1110 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1111 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1112 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1113 if (side[0] + side[1] + side[2] == 0)
1117 element = inelement3i + markindex;
1119 // create the vertices
1120 for (j = 0;j < 3;j++)
1122 if (side[j] + side[j+1] == 0)
1125 if (vertexupdate[k] != vertexupdatenum)
1127 vertexupdate[k] = vertexupdatenum;
1128 vertexremap[k] = outvertices;
1129 vertex = invertex3f + k * 3;
1130 VectorCopy(vertex, outvertex3f);
1131 if (projectdirection)
1133 // project one copy of the vertex according to projectvector
1134 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1138 // project one copy of the vertex to the sphere radius of the light
1139 // (FIXME: would projecting it to the light box be better?)
1140 VectorSubtract(vertex, projectorigin, direction);
1141 ratio = projectdistance / VectorLength(direction);
1142 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1149 // output the sides (facing outward from this triangle)
1152 remappedelement[0] = vertexremap[element[0]];
1153 remappedelement[1] = vertexremap[element[1]];
1154 outelement3i[0] = remappedelement[1];
1155 outelement3i[1] = remappedelement[0];
1156 outelement3i[2] = remappedelement[0] + 1;
1157 outelement3i[3] = remappedelement[1];
1158 outelement3i[4] = remappedelement[0] + 1;
1159 outelement3i[5] = remappedelement[1] + 1;
1166 remappedelement[1] = vertexremap[element[1]];
1167 remappedelement[2] = vertexremap[element[2]];
1168 outelement3i[0] = remappedelement[2];
1169 outelement3i[1] = remappedelement[1];
1170 outelement3i[2] = remappedelement[1] + 1;
1171 outelement3i[3] = remappedelement[2];
1172 outelement3i[4] = remappedelement[1] + 1;
1173 outelement3i[5] = remappedelement[2] + 1;
1180 remappedelement[0] = vertexremap[element[0]];
1181 remappedelement[2] = vertexremap[element[2]];
1182 outelement3i[0] = remappedelement[0];
1183 outelement3i[1] = remappedelement[2];
1184 outelement3i[2] = remappedelement[2] + 1;
1185 outelement3i[3] = remappedelement[0];
1186 outelement3i[4] = remappedelement[2] + 1;
1187 outelement3i[5] = remappedelement[0] + 1;
1194 *outnumvertices = outvertices;
1195 return outtriangles;
1198 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)
1204 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1206 tend = firsttriangle + numtris;
1207 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1209 // surface box entirely inside light box, no box cull
1210 if (projectdirection)
1212 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1214 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1215 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1216 shadowmarklist[numshadowmark++] = t;
1221 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1222 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1223 shadowmarklist[numshadowmark++] = t;
1228 // surface box not entirely inside light box, cull each triangle
1229 if (projectdirection)
1231 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1233 v[0] = invertex3f + e[0] * 3;
1234 v[1] = invertex3f + e[1] * 3;
1235 v[2] = invertex3f + e[2] * 3;
1236 TriangleNormal(v[0], v[1], v[2], normal);
1237 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1238 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1239 shadowmarklist[numshadowmark++] = t;
1244 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1246 v[0] = invertex3f + e[0] * 3;
1247 v[1] = invertex3f + e[1] * 3;
1248 v[2] = invertex3f + e[2] * 3;
1249 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1250 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1251 shadowmarklist[numshadowmark++] = t;
1257 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1262 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1264 // check if the shadow volume intersects the near plane
1266 // a ray between the eye and light origin may intersect the caster,
1267 // indicating that the shadow may touch the eye location, however we must
1268 // test the near plane (a polygon), not merely the eye location, so it is
1269 // easiest to enlarge the caster bounding shape slightly for this.
1275 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)
1277 int i, tris, outverts;
1278 if (projectdistance < 0.1)
1280 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1283 if (!numverts || !nummarktris)
1285 // make sure shadowelements is big enough for this volume
1286 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1287 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1289 if (maxvertexupdate < numverts)
1291 maxvertexupdate = numverts;
1293 Mem_Free(vertexupdate);
1295 Mem_Free(vertexremap);
1296 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1297 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1298 vertexupdatenum = 0;
1301 if (vertexupdatenum == 0)
1303 vertexupdatenum = 1;
1304 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1305 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1308 for (i = 0;i < nummarktris;i++)
1309 shadowmark[marktris[i]] = shadowmarkcount;
1311 if (r_shadow_compilingrtlight)
1313 // if we're compiling an rtlight, capture the mesh
1314 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1315 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1316 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1317 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1319 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1321 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1322 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1323 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1327 // decide which type of shadow to generate and set stencil mode
1328 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1329 // generate the sides or a solid volume, depending on type
1330 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1331 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1333 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1334 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1335 r_refdef.stats.lights_shadowtriangles += tris;
1337 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1338 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1340 // increment stencil if frontface is infront of depthbuffer
1341 GL_CullFace(r_refdef.view.cullface_front);
1342 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1343 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1344 // decrement stencil if backface is infront of depthbuffer
1345 GL_CullFace(r_refdef.view.cullface_back);
1346 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1348 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1350 // decrement stencil if backface is behind depthbuffer
1351 GL_CullFace(r_refdef.view.cullface_front);
1352 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1353 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1354 // increment stencil if frontface is behind depthbuffer
1355 GL_CullFace(r_refdef.view.cullface_back);
1356 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1358 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1363 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1365 // p1, p2, p3 are in the cubemap's local coordinate system
1366 // bias = border/(size - border)
1369 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1370 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1371 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1372 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1374 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1375 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1376 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1377 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1379 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1380 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1381 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1383 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1384 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1385 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1386 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1388 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1389 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1390 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1391 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1393 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1394 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1395 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1397 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1398 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1399 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1400 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1402 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1403 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1404 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1405 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1407 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1408 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1409 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1414 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1416 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1417 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1420 VectorSubtract(maxs, mins, radius);
1421 VectorScale(radius, 0.5f, radius);
1422 VectorAdd(mins, radius, center);
1423 Matrix4x4_Transform(worldtolight, center, lightcenter);
1424 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1425 VectorSubtract(lightcenter, lightradius, pmin);
1426 VectorAdd(lightcenter, lightradius, pmax);
1428 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1429 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1430 if(ap1 > bias*an1 && ap2 > bias*an2)
1432 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1433 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1434 if(an1 > bias*ap1 && an2 > bias*ap2)
1436 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1437 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1439 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1440 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1441 if(ap1 > bias*an1 && ap2 > bias*an2)
1443 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1444 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1445 if(an1 > bias*ap1 && an2 > bias*ap2)
1447 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1448 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1450 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1451 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1452 if(ap1 > bias*an1 && ap2 > bias*an2)
1454 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1455 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1456 if(an1 > bias*ap1 && an2 > bias*ap2)
1458 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1459 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1464 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1466 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1468 // p is in the cubemap's local coordinate system
1469 // bias = border/(size - border)
1470 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1471 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1472 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1474 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1475 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1476 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1477 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1478 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1479 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1483 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1487 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1488 float scale = (size - 2*border)/size, len;
1489 float bias = border / (float)(size - border), dp, dn, ap, an;
1490 // check if cone enclosing side would cross frustum plane
1491 scale = 2 / (scale*scale + 2);
1492 for (i = 0;i < 5;i++)
1494 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1496 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1497 len = scale*VectorLength2(n);
1498 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1499 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1500 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1502 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1504 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1505 len = scale*VectorLength(n);
1506 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1507 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1508 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1510 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1511 // check if frustum corners/origin cross plane sides
1512 for (i = 0;i < 5;i++)
1514 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1515 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn),
1516 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1517 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1518 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn),
1519 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1520 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1521 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn),
1522 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1523 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1525 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1528 int R_Shadow_ChooseSidesFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const matrix4x4_t *worldtolight, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs, int *totals)
1536 int mask, surfacemask = 0;
1537 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1539 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1540 tend = firsttriangle + numtris;
1541 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1543 // surface box entirely inside light box, no box cull
1544 if (projectdirection)
1546 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1548 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1549 TriangleNormal(v[0], v[1], v[2], normal);
1550 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1552 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1553 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1554 surfacemask |= mask;
1557 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1558 shadowsides[numshadowsides] = mask;
1559 shadowsideslist[numshadowsides++] = t;
1566 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1568 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1569 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1571 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1572 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1573 surfacemask |= mask;
1576 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1577 shadowsides[numshadowsides] = mask;
1578 shadowsideslist[numshadowsides++] = t;
1586 // surface box not entirely inside light box, cull each triangle
1587 if (projectdirection)
1589 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1591 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1592 TriangleNormal(v[0], v[1], v[2], normal);
1593 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1594 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1596 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1597 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1598 surfacemask |= mask;
1601 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1602 shadowsides[numshadowsides] = mask;
1603 shadowsideslist[numshadowsides++] = t;
1610 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1612 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1613 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1614 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1616 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1617 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1618 surfacemask |= mask;
1621 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1622 shadowsides[numshadowsides] = mask;
1623 shadowsideslist[numshadowsides++] = t;
1632 void R_Shadow_ShadowMapFromList(int numverts, int numtris, const float *vertex3f, const int *elements, int numsidetris, const int *sidetotals, const unsigned char *sides, const int *sidetris)
1634 int i, j, outtriangles = 0;
1635 int *outelement3i[6];
1636 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1638 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1639 // make sure shadowelements is big enough for this mesh
1640 if (maxshadowtriangles < outtriangles)
1641 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1643 // compute the offset and size of the separate index lists for each cubemap side
1645 for (i = 0;i < 6;i++)
1647 outelement3i[i] = shadowelements + outtriangles * 3;
1648 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1649 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1650 outtriangles += sidetotals[i];
1653 // gather up the (sparse) triangles into separate index lists for each cubemap side
1654 for (i = 0;i < numsidetris;i++)
1656 const int *element = elements + sidetris[i] * 3;
1657 for (j = 0;j < 6;j++)
1659 if (sides[i] & (1 << j))
1661 outelement3i[j][0] = element[0];
1662 outelement3i[j][1] = element[1];
1663 outelement3i[j][2] = element[2];
1664 outelement3i[j] += 3;
1669 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1672 static void R_Shadow_MakeTextures_MakeCorona(void)
1676 unsigned char pixels[32][32][4];
1677 for (y = 0;y < 32;y++)
1679 dy = (y - 15.5f) * (1.0f / 16.0f);
1680 for (x = 0;x < 32;x++)
1682 dx = (x - 15.5f) * (1.0f / 16.0f);
1683 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1684 a = bound(0, a, 255);
1685 pixels[y][x][0] = a;
1686 pixels[y][x][1] = a;
1687 pixels[y][x][2] = a;
1688 pixels[y][x][3] = 255;
1691 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1694 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1696 float dist = sqrt(x*x+y*y+z*z);
1697 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1698 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1699 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1702 static void R_Shadow_MakeTextures(void)
1705 float intensity, dist;
1707 R_Shadow_FreeShadowMaps();
1708 R_FreeTexturePool(&r_shadow_texturepool);
1709 r_shadow_texturepool = R_AllocTexturePool();
1710 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1711 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1712 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1713 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1714 for (x = 0;x <= ATTENTABLESIZE;x++)
1716 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1717 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1718 r_shadow_attentable[x] = bound(0, intensity, 1);
1720 // 1D gradient texture
1721 for (x = 0;x < ATTEN1DSIZE;x++)
1722 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1723 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1724 // 2D circle texture
1725 for (y = 0;y < ATTEN2DSIZE;y++)
1726 for (x = 0;x < ATTEN2DSIZE;x++)
1727 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);
1728 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1729 // 3D sphere texture
1730 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1732 for (z = 0;z < ATTEN3DSIZE;z++)
1733 for (y = 0;y < ATTEN3DSIZE;y++)
1734 for (x = 0;x < ATTEN3DSIZE;x++)
1735 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));
1736 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1739 r_shadow_attenuation3dtexture = NULL;
1742 R_Shadow_MakeTextures_MakeCorona();
1744 // Editor light sprites
1745 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1762 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1763 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1780 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1781 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1798 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1799 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1816 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1817 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1834 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1835 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1852 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1855 void R_Shadow_ValidateCvars(void)
1857 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1858 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1859 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1860 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1861 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1862 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1865 void R_Shadow_RenderMode_Begin(void)
1871 R_Shadow_ValidateCvars();
1873 if (!r_shadow_attenuation2dtexture
1874 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1875 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1876 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1877 R_Shadow_MakeTextures();
1880 R_Mesh_ColorPointer(NULL, 0, 0);
1881 R_Mesh_ResetTextureState();
1882 GL_BlendFunc(GL_ONE, GL_ZERO);
1883 GL_DepthRange(0, 1);
1884 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1886 GL_DepthMask(false);
1887 GL_Color(0, 0, 0, 1);
1888 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1890 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1892 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1894 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1895 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1897 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1899 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1900 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1904 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1905 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1908 switch(vid.renderpath)
1910 case RENDERPATH_GL20:
1911 case RENDERPATH_CGGL:
1912 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1914 case RENDERPATH_GL13:
1915 case RENDERPATH_GL11:
1916 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1917 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1918 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1919 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1920 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1921 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1923 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1929 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1930 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1931 r_shadow_drawbuffer = drawbuffer;
1932 r_shadow_readbuffer = readbuffer;
1934 r_shadow_cullface_front = r_refdef.view.cullface_front;
1935 r_shadow_cullface_back = r_refdef.view.cullface_back;
1938 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1940 rsurface.rtlight = rtlight;
1943 void R_Shadow_RenderMode_Reset(void)
1946 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1948 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1950 if (vid.support.ext_framebuffer_object)
1952 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1955 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1956 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1958 R_SetViewport(&r_refdef.view.viewport);
1959 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1960 R_Mesh_ColorPointer(NULL, 0, 0);
1961 R_Mesh_ResetTextureState();
1962 GL_DepthRange(0, 1);
1964 GL_DepthMask(false);
1965 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1966 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1967 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1968 qglStencilMask(255);CHECKGLERROR
1969 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1970 qglStencilFunc(GL_ALWAYS, 128, 255);CHECKGLERROR
1971 r_refdef.view.cullface_front = r_shadow_cullface_front;
1972 r_refdef.view.cullface_back = r_shadow_cullface_back;
1973 GL_CullFace(r_refdef.view.cullface_back);
1974 GL_Color(1, 1, 1, 1);
1975 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1976 GL_BlendFunc(GL_ONE, GL_ZERO);
1977 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1978 r_shadow_usingshadowmaprect = false;
1979 r_shadow_usingshadowmapcube = false;
1980 r_shadow_usingshadowmap2d = false;
1984 void R_Shadow_ClearStencil(void)
1987 GL_Clear(GL_STENCIL_BUFFER_BIT);
1988 r_refdef.stats.lights_clears++;
1991 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1993 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1994 if (r_shadow_rendermode == mode)
1997 R_Shadow_RenderMode_Reset();
1998 GL_ColorMask(0, 0, 0, 0);
1999 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2000 R_SetupShader_DepthOrShadow();
2001 qglDepthFunc(GL_LESS);CHECKGLERROR
2002 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2003 r_shadow_rendermode = mode;
2008 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2009 GL_CullFace(GL_NONE);
2010 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
2011 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
2013 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2014 GL_CullFace(GL_NONE);
2015 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2016 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2018 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2019 GL_CullFace(GL_NONE);
2020 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
2021 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2022 qglStencilMask(255);CHECKGLERROR
2023 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
2024 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2025 qglStencilMask(255);CHECKGLERROR
2026 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
2028 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2029 GL_CullFace(GL_NONE);
2030 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
2031 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2032 qglStencilMask(255);CHECKGLERROR
2033 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2034 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2035 qglStencilMask(255);CHECKGLERROR
2036 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2041 static void R_Shadow_MakeVSDCT(void)
2043 // maps to a 2x3 texture rectangle with normalized coordinates
2048 // stores abs(dir.xy), offset.xy/2.5
2049 unsigned char data[4*6] =
2051 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2052 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2053 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2054 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2055 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2056 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2058 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
2061 static void R_Shadow_MakeShadowMap(int side, int size)
2064 switch (r_shadow_shadowmode)
2066 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2067 if (r_shadow_shadowmap2dtexture) return;
2068 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2069 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
2070 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
2071 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
2073 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2074 if (r_shadow_shadowmaprectangletexture) return;
2075 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", size*2, size*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2076 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
2077 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
2078 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
2080 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2081 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) return;
2082 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2083 qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2084 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2085 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR
2090 // render depth into the fbo, do not render color at all
2091 qglDrawBuffer(GL_NONE);CHECKGLERROR
2092 qglReadBuffer(GL_NONE);CHECKGLERROR
2093 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2094 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2096 Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2097 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2098 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2102 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2104 float nearclip, farclip, bias;
2105 r_viewport_t viewport;
2109 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2111 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2112 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2113 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2114 r_shadow_shadowmapside = side;
2115 r_shadow_shadowmapsize = size;
2116 switch (r_shadow_shadowmode)
2118 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2119 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2120 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2121 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2122 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2124 // complex unrolled cube approach (more flexible)
2125 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2126 R_Shadow_MakeVSDCT();
2127 if (!r_shadow_shadowmap2dtexture)
2128 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2130 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2131 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2132 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2133 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2135 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2136 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2137 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2138 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2139 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
2141 // complex unrolled cube approach (more flexible)
2142 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2143 R_Shadow_MakeVSDCT();
2144 if (!r_shadow_shadowmaprectangletexture)
2145 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2147 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
2148 r_shadow_shadowmap_texturescale[0] = 1.0f;
2149 r_shadow_shadowmap_texturescale[1] = 1.0f;
2150 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
2152 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2153 r_shadow_shadowmap_parameters[0] = 1.0f;
2154 r_shadow_shadowmap_parameters[1] = 1.0f;
2155 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2156 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2158 // simple cube approach
2159 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2160 R_Shadow_MakeShadowMap(side, size);
2162 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
2163 r_shadow_shadowmap_texturescale[0] = 0.0f;
2164 r_shadow_shadowmap_texturescale[1] = 0.0f;
2165 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2171 R_Shadow_RenderMode_Reset();
2174 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
2175 R_SetupShader_DepthOrShadow();
2179 R_SetupShader_ShowDepth();
2180 qglClearColor(1,1,1,1);CHECKGLERROR
2183 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2190 R_SetViewport(&viewport);
2191 switch (r_shadow_rendermode)
2193 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
2194 case R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE:
2195 flipped = (side & 1) ^ (side >> 2);
2196 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2197 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2198 GL_CullFace(r_refdef.view.cullface_back);
2199 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2201 // get tightest scissor rectangle that encloses all viewports in the clear mask
2202 int x1 = clear & 0x15 ? 0 : size;
2203 int x2 = clear & 0x2A ? 2 * size : size;
2204 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2205 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2206 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2207 GL_Clear(GL_DEPTH_BUFFER_BIT);
2209 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2211 case R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE:
2212 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR
2213 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2215 GL_Clear(GL_DEPTH_BUFFER_BIT);
2223 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2227 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2228 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2229 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2230 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2233 R_Shadow_RenderMode_Reset();
2234 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2237 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2241 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2242 // only draw light where this geometry was already rendered AND the
2243 // stencil is 128 (values other than this mean shadow)
2244 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2246 r_shadow_rendermode = r_shadow_lightingrendermode;
2247 // do global setup needed for the chosen lighting mode
2248 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2250 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2255 switch (r_shadow_shadowmode)
2257 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2258 r_shadow_usingshadowmap2d = true;
2260 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2261 r_shadow_usingshadowmaprect = true;
2263 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2264 r_shadow_usingshadowmapcube = true;
2270 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2274 static const unsigned short bboxelements[36] =
2284 static const float bboxpoints[8][3] =
2296 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2299 float vertex3f[8*3];
2300 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2302 R_Shadow_RenderMode_Reset();
2303 r_shadow_rendermode = r_shadow_lightingrendermode;
2304 // do global setup needed for the chosen lighting mode
2306 R_EntityMatrix(&identitymatrix);
2307 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2310 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2311 // only draw light where this geometry was already rendered AND the
2312 // stencil is 128 (values other than this mean shadow)
2313 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2315 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
2318 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2319 r_shadow_usingshadowmap2d = true;
2320 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2321 r_shadow_usingshadowmaprect = true;
2322 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2323 r_shadow_usingshadowmapcube = true;
2326 // render the lighting
2327 R_SetupShader_DeferredLight(rsurface.rtlight);
2328 for (i = 0;i < 8;i++)
2329 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2331 R_Mesh_VertexPointer(vertex3f, 0, 0);
2332 R_Mesh_ColorPointer(NULL, 0, 0);
2333 GL_ColorMask(1,1,1,1);
2334 GL_DepthMask(false);
2335 GL_DepthRange(0, 1);
2336 GL_PolygonOffset(0, 0);
2338 qglDepthFunc(GL_GREATER);CHECKGLERROR
2339 GL_CullFace(r_refdef.view.cullface_back);
2340 R_Mesh_Draw(0, 8, 0, 12, NULL, bboxelements, 0, 0);
2344 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2347 R_Shadow_RenderMode_Reset();
2348 GL_BlendFunc(GL_ONE, GL_ONE);
2349 GL_DepthRange(0, 1);
2350 GL_DepthTest(r_showshadowvolumes.integer < 2);
2351 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2352 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2353 GL_CullFace(GL_NONE);
2354 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2357 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2360 R_Shadow_RenderMode_Reset();
2361 GL_BlendFunc(GL_ONE, GL_ONE);
2362 GL_DepthRange(0, 1);
2363 GL_DepthTest(r_showlighting.integer < 2);
2364 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2367 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2371 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2372 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2374 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2377 void R_Shadow_RenderMode_End(void)
2380 R_Shadow_RenderMode_Reset();
2381 R_Shadow_RenderMode_ActiveLight(NULL);
2383 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2384 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2387 int bboxedges[12][2] =
2406 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2408 int i, ix1, iy1, ix2, iy2;
2409 float x1, y1, x2, y2;
2411 float vertex[20][3];
2420 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2421 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2422 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2423 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2425 if (!r_shadow_scissor.integer)
2428 // if view is inside the light box, just say yes it's visible
2429 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2432 x1 = y1 = x2 = y2 = 0;
2434 // transform all corners that are infront of the nearclip plane
2435 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2436 plane4f[3] = r_refdef.view.frustum[4].dist;
2438 for (i = 0;i < 8;i++)
2440 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2441 dist[i] = DotProduct4(corner[i], plane4f);
2442 sign[i] = dist[i] > 0;
2445 VectorCopy(corner[i], vertex[numvertices]);
2449 // if some points are behind the nearclip, add clipped edge points to make
2450 // sure that the scissor boundary is complete
2451 if (numvertices > 0 && numvertices < 8)
2453 // add clipped edge points
2454 for (i = 0;i < 12;i++)
2456 j = bboxedges[i][0];
2457 k = bboxedges[i][1];
2458 if (sign[j] != sign[k])
2460 f = dist[j] / (dist[j] - dist[k]);
2461 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2467 // if we have no points to check, the light is behind the view plane
2471 // if we have some points to transform, check what screen area is covered
2472 x1 = y1 = x2 = y2 = 0;
2474 //Con_Printf("%i vertices to transform...\n", numvertices);
2475 for (i = 0;i < numvertices;i++)
2477 VectorCopy(vertex[i], v);
2478 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2479 //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]);
2482 if (x1 > v2[0]) x1 = v2[0];
2483 if (x2 < v2[0]) x2 = v2[0];
2484 if (y1 > v2[1]) y1 = v2[1];
2485 if (y2 < v2[1]) y2 = v2[1];
2494 // now convert the scissor rectangle to integer screen coordinates
2495 ix1 = (int)(x1 - 1.0f);
2496 iy1 = vid.height - (int)(y2 - 1.0f);
2497 ix2 = (int)(x2 + 1.0f);
2498 iy2 = vid.height - (int)(y1 + 1.0f);
2499 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2501 // clamp it to the screen
2502 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2503 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2504 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2505 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2507 // if it is inside out, it's not visible
2508 if (ix2 <= ix1 || iy2 <= iy1)
2511 // the light area is visible, set up the scissor rectangle
2512 r_shadow_lightscissor[0] = ix1;
2513 r_shadow_lightscissor[1] = iy1;
2514 r_shadow_lightscissor[2] = ix2 - ix1;
2515 r_shadow_lightscissor[3] = iy2 - iy1;
2517 r_refdef.stats.lights_scissored++;
2521 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2523 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2524 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2525 float *color4f = rsurface.array_color4f + 4 * firstvertex;
2526 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2527 switch (r_shadow_rendermode)
2529 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2530 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2531 if (VectorLength2(diffusecolor) > 0)
2533 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2535 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2536 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2537 if ((dot = DotProduct(n, v)) < 0)
2539 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2540 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2543 VectorCopy(ambientcolor, color4f);
2544 if (r_refdef.fogenabled)
2547 f = RSurf_FogVertex(vertex3f);
2548 VectorScale(color4f, f, color4f);
2555 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2557 VectorCopy(ambientcolor, color4f);
2558 if (r_refdef.fogenabled)
2561 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2562 f = RSurf_FogVertex(vertex3f);
2563 VectorScale(color4f, f, color4f);
2569 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2570 if (VectorLength2(diffusecolor) > 0)
2572 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2574 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2575 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2577 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2578 if ((dot = DotProduct(n, v)) < 0)
2580 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2581 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2582 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2583 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2587 color4f[0] = ambientcolor[0] * distintensity;
2588 color4f[1] = ambientcolor[1] * distintensity;
2589 color4f[2] = ambientcolor[2] * distintensity;
2591 if (r_refdef.fogenabled)
2594 f = RSurf_FogVertex(vertex3f);
2595 VectorScale(color4f, f, color4f);
2599 VectorClear(color4f);
2605 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2607 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2608 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2610 color4f[0] = ambientcolor[0] * distintensity;
2611 color4f[1] = ambientcolor[1] * distintensity;
2612 color4f[2] = ambientcolor[2] * distintensity;
2613 if (r_refdef.fogenabled)
2616 f = RSurf_FogVertex(vertex3f);
2617 VectorScale(color4f, f, color4f);
2621 VectorClear(color4f);
2626 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2627 if (VectorLength2(diffusecolor) > 0)
2629 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2631 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2632 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2634 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2635 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2636 if ((dot = DotProduct(n, v)) < 0)
2638 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2639 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2640 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2641 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2645 color4f[0] = ambientcolor[0] * distintensity;
2646 color4f[1] = ambientcolor[1] * distintensity;
2647 color4f[2] = ambientcolor[2] * distintensity;
2649 if (r_refdef.fogenabled)
2652 f = RSurf_FogVertex(vertex3f);
2653 VectorScale(color4f, f, color4f);
2657 VectorClear(color4f);
2663 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2665 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2666 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2668 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2669 color4f[0] = ambientcolor[0] * distintensity;
2670 color4f[1] = ambientcolor[1] * distintensity;
2671 color4f[2] = ambientcolor[2] * distintensity;
2672 if (r_refdef.fogenabled)
2675 f = RSurf_FogVertex(vertex3f);
2676 VectorScale(color4f, f, color4f);
2680 VectorClear(color4f);
2690 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)
2692 // used to display how many times a surface is lit for level design purposes
2693 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2696 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 lightcolor, float ambientscale, float diffusescale, float specularscale)
2698 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2699 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2700 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2702 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2704 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2705 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2707 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2711 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2718 int newnumtriangles;
2722 int maxtriangles = 4096;
2723 static int newelements[4096*3];
2724 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2725 for (renders = 0;renders < 4;renders++)
2730 newnumtriangles = 0;
2732 // due to low fillrate on the cards this vertex lighting path is
2733 // designed for, we manually cull all triangles that do not
2734 // contain a lit vertex
2735 // this builds batches of triangles from multiple surfaces and
2736 // renders them at once
2737 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2739 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2741 if (newnumtriangles)
2743 newfirstvertex = min(newfirstvertex, e[0]);
2744 newlastvertex = max(newlastvertex, e[0]);
2748 newfirstvertex = e[0];
2749 newlastvertex = e[0];
2751 newfirstvertex = min(newfirstvertex, e[1]);
2752 newlastvertex = max(newlastvertex, e[1]);
2753 newfirstvertex = min(newfirstvertex, e[2]);
2754 newlastvertex = max(newlastvertex, e[2]);
2760 if (newnumtriangles >= maxtriangles)
2762 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2763 newnumtriangles = 0;
2769 if (newnumtriangles >= 1)
2771 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2774 // if we couldn't find any lit triangles, exit early
2777 // now reduce the intensity for the next overbright pass
2778 // we have to clamp to 0 here incase the drivers have improper
2779 // handling of negative colors
2780 // (some old drivers even have improper handling of >1 color)
2782 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2784 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2786 c[0] = max(0, c[0] - 1);
2787 c[1] = max(0, c[1] - 1);
2788 c[2] = max(0, c[2] - 1);
2800 static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolor, float ambientscale, float diffusescale)
2802 // OpenGL 1.1 path (anything)
2803 float ambientcolorbase[3], diffusecolorbase[3];
2804 float ambientcolorpants[3], diffusecolorpants[3];
2805 float ambientcolorshirt[3], diffusecolorshirt[3];
2806 const float *surfacecolor = rsurface.texture->dlightcolor;
2807 const float *surfacepants = rsurface.colormap_pantscolor;
2808 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2809 rtexture_t *basetexture = rsurface.texture->basetexture;
2810 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2811 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2812 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2813 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2814 ambientscale *= 2 * r_refdef.view.colorscale;
2815 diffusescale *= 2 * r_refdef.view.colorscale;
2816 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2817 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2818 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2819 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2820 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2821 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2822 R_Mesh_TexBind(0, basetexture);
2823 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2824 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2825 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2826 switch(r_shadow_rendermode)
2828 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2829 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2830 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2831 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2832 R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2834 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2835 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2836 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2837 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2838 R_Mesh_TexCoordPointer(2, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2840 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2841 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
2842 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2843 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2844 R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2846 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2851 //R_Mesh_TexBind(0, basetexture);
2852 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2855 R_Mesh_TexBind(0, pantstexture);
2856 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2860 R_Mesh_TexBind(0, shirttexture);
2861 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2865 extern cvar_t gl_lightmaps;
2866 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)
2868 float ambientscale, diffusescale, specularscale;
2870 float lightcolor[3];
2871 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2872 ambientscale = rsurface.rtlight->ambientscale;
2873 diffusescale = rsurface.rtlight->diffusescale;
2874 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2875 if (!r_shadow_usenormalmap.integer)
2877 ambientscale += 1.0f * diffusescale;
2881 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2883 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2886 VectorNegate(lightcolor, lightcolor);
2887 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2889 RSurf_SetupDepthAndCulling();
2890 switch (r_shadow_rendermode)
2892 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2893 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2894 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2896 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2897 R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolor, ambientscale, diffusescale, specularscale);
2899 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2900 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2901 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2902 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2903 R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i + firsttriangle * 3, lightcolor, ambientscale, diffusescale);
2906 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2910 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2913 void R_RTLight_Update(rtlight_t *rtlight, int isstatic, matrix4x4_t *matrix, vec3_t color, int style, const char *cubemapname, int shadow, vec_t corona, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
2915 matrix4x4_t tempmatrix = *matrix;
2916 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2918 // if this light has been compiled before, free the associated data
2919 R_RTLight_Uncompile(rtlight);
2921 // clear it completely to avoid any lingering data
2922 memset(rtlight, 0, sizeof(*rtlight));
2924 // copy the properties
2925 rtlight->matrix_lighttoworld = tempmatrix;
2926 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2927 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2928 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2929 VectorCopy(color, rtlight->color);
2930 rtlight->cubemapname[0] = 0;
2931 if (cubemapname && cubemapname[0])
2932 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2933 rtlight->shadow = shadow;
2934 rtlight->corona = corona;
2935 rtlight->style = style;
2936 rtlight->isstatic = isstatic;
2937 rtlight->coronasizescale = coronasizescale;
2938 rtlight->ambientscale = ambientscale;
2939 rtlight->diffusescale = diffusescale;
2940 rtlight->specularscale = specularscale;
2941 rtlight->flags = flags;
2943 // compute derived data
2944 //rtlight->cullradius = rtlight->radius;
2945 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2946 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2947 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2948 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2949 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2950 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2951 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2954 // compiles rtlight geometry
2955 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2956 void R_RTLight_Compile(rtlight_t *rtlight)
2959 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2960 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2961 entity_render_t *ent = r_refdef.scene.worldentity;
2962 dp_model_t *model = r_refdef.scene.worldmodel;
2963 unsigned char *data;
2966 // compile the light
2967 rtlight->compiled = true;
2968 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
2969 rtlight->static_numleafs = 0;
2970 rtlight->static_numleafpvsbytes = 0;
2971 rtlight->static_leaflist = NULL;
2972 rtlight->static_leafpvs = NULL;
2973 rtlight->static_numsurfaces = 0;
2974 rtlight->static_surfacelist = NULL;
2975 rtlight->static_shadowmap_receivers = 0x3F;
2976 rtlight->static_shadowmap_casters = 0x3F;
2977 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2978 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2979 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2980 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2981 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2982 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2984 if (model && model->GetLightInfo)
2986 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
2987 r_shadow_compilingrtlight = rtlight;
2988 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, 0, NULL);
2989 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2990 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2991 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2992 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2993 rtlight->static_numsurfaces = numsurfaces;
2994 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2995 rtlight->static_numleafs = numleafs;
2996 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2997 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2998 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2999 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3000 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3001 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3002 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3003 if (rtlight->static_numsurfaces)
3004 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3005 if (rtlight->static_numleafs)
3006 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3007 if (rtlight->static_numleafpvsbytes)
3008 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3009 if (rtlight->static_numshadowtrispvsbytes)
3010 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3011 if (rtlight->static_numlighttrispvsbytes)
3012 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3013 switch (rtlight->shadowmode)
3015 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3016 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
3017 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
3018 if (model->CompileShadowMap && rtlight->shadow)
3019 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3022 if (model->CompileShadowVolume && rtlight->shadow)
3023 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3026 // now we're done compiling the rtlight
3027 r_shadow_compilingrtlight = NULL;
3031 // use smallest available cullradius - box radius or light radius
3032 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3033 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3035 shadowzpasstris = 0;
3036 if (rtlight->static_meshchain_shadow_zpass)
3037 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3038 shadowzpasstris += mesh->numtriangles;
3040 shadowzfailtris = 0;
3041 if (rtlight->static_meshchain_shadow_zfail)
3042 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3043 shadowzfailtris += mesh->numtriangles;
3046 if (rtlight->static_numlighttrispvsbytes)
3047 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3048 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3052 if (rtlight->static_numlighttrispvsbytes)
3053 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3054 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3057 if (developer_extra.integer)
3058 Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i light triangles, %i shadow triangles, %i zpass/%i zfail compiled shadow volume triangles\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], lighttris, shadowtris, shadowzpasstris, shadowzfailtris);
3061 void R_RTLight_Uncompile(rtlight_t *rtlight)
3063 if (rtlight->compiled)
3065 if (rtlight->static_meshchain_shadow_zpass)
3066 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3067 rtlight->static_meshchain_shadow_zpass = NULL;
3068 if (rtlight->static_meshchain_shadow_zfail)
3069 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3070 rtlight->static_meshchain_shadow_zfail = NULL;
3071 if (rtlight->static_meshchain_shadow_shadowmap)
3072 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3073 rtlight->static_meshchain_shadow_shadowmap = NULL;
3074 // these allocations are grouped
3075 if (rtlight->static_surfacelist)
3076 Mem_Free(rtlight->static_surfacelist);
3077 rtlight->static_numleafs = 0;
3078 rtlight->static_numleafpvsbytes = 0;
3079 rtlight->static_leaflist = NULL;
3080 rtlight->static_leafpvs = NULL;
3081 rtlight->static_numsurfaces = 0;
3082 rtlight->static_surfacelist = NULL;
3083 rtlight->static_numshadowtrispvsbytes = 0;
3084 rtlight->static_shadowtrispvs = NULL;
3085 rtlight->static_numlighttrispvsbytes = 0;
3086 rtlight->static_lighttrispvs = NULL;
3087 rtlight->compiled = false;
3091 void R_Shadow_UncompileWorldLights(void)
3095 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3096 for (lightindex = 0;lightindex < range;lightindex++)
3098 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3101 R_RTLight_Uncompile(&light->rtlight);
3105 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3109 // reset the count of frustum planes
3110 // see rtlight->cached_frustumplanes definition for how much this array
3112 rtlight->cached_numfrustumplanes = 0;
3114 // haven't implemented a culling path for ortho rendering
3115 if (!r_refdef.view.useperspective)
3117 // check if the light is on screen and copy the 4 planes if it is
3118 for (i = 0;i < 4;i++)
3119 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3122 for (i = 0;i < 4;i++)
3123 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3128 // generate a deformed frustum that includes the light origin, this is
3129 // used to cull shadow casting surfaces that can not possibly cast a
3130 // shadow onto the visible light-receiving surfaces, which can be a
3133 // if the light origin is onscreen the result will be 4 planes exactly
3134 // if the light origin is offscreen on only one axis the result will
3135 // be exactly 5 planes (split-side case)
3136 // if the light origin is offscreen on two axes the result will be
3137 // exactly 4 planes (stretched corner case)
3138 for (i = 0;i < 4;i++)
3140 // quickly reject standard frustum planes that put the light
3141 // origin outside the frustum
3142 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3145 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3147 // if all the standard frustum planes were accepted, the light is onscreen
3148 // otherwise we need to generate some more planes below...
3149 if (rtlight->cached_numfrustumplanes < 4)
3151 // at least one of the stock frustum planes failed, so we need to
3152 // create one or two custom planes to enclose the light origin
3153 for (i = 0;i < 4;i++)
3155 // create a plane using the view origin and light origin, and a
3156 // single point from the frustum corner set
3157 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3158 VectorNormalize(plane.normal);
3159 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3160 // see if this plane is backwards and flip it if so
3161 for (j = 0;j < 4;j++)
3162 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3166 VectorNegate(plane.normal, plane.normal);
3168 // flipped plane, test again to see if it is now valid
3169 for (j = 0;j < 4;j++)
3170 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3172 // if the plane is still not valid, then it is dividing the
3173 // frustum and has to be rejected
3177 // we have created a valid plane, compute extra info
3178 PlaneClassify(&plane);
3180 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3182 // if we've found 5 frustum planes then we have constructed a
3183 // proper split-side case and do not need to keep searching for
3184 // planes to enclose the light origin
3185 if (rtlight->cached_numfrustumplanes == 5)
3193 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3195 plane = rtlight->cached_frustumplanes[i];
3196 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));
3201 // now add the light-space box planes if the light box is rotated, as any
3202 // caster outside the oriented light box is irrelevant (even if it passed
3203 // the worldspace light box, which is axial)
3204 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3206 for (i = 0;i < 6;i++)
3210 v[i >> 1] = (i & 1) ? -1 : 1;
3211 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3212 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3213 plane.dist = VectorNormalizeLength(plane.normal);
3214 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3215 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3221 // add the world-space reduced box planes
3222 for (i = 0;i < 6;i++)
3224 VectorClear(plane.normal);
3225 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3226 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3227 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3236 // reduce all plane distances to tightly fit the rtlight cull box, which
3238 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3239 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3240 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3241 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3242 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3243 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3244 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3245 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3246 oldnum = rtlight->cached_numfrustumplanes;
3247 rtlight->cached_numfrustumplanes = 0;
3248 for (j = 0;j < oldnum;j++)
3250 // find the nearest point on the box to this plane
3251 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3252 for (i = 1;i < 8;i++)
3254 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3255 if (bestdist > dist)
3258 Con_Printf("light %p %splane #%i %f %f %f : %f < %f\n", rtlight, rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125 ? "^2" : "^1", j, rtlight->cached_frustumplanes[j].normal[0], rtlight->cached_frustumplanes[j].normal[1], rtlight->cached_frustumplanes[j].normal[2], rtlight->cached_frustumplanes[j].dist, bestdist);
3259 // if the nearest point is near or behind the plane, we want this
3260 // plane, otherwise the plane is useless as it won't cull anything
3261 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3263 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3264 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3271 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3275 RSurf_ActiveWorldEntity();
3277 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3280 GL_CullFace(GL_NONE);
3281 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3282 for (;mesh;mesh = mesh->next)
3284 if (!mesh->sidetotals[r_shadow_shadowmapside])
3286 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3287 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3288 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3292 else if (r_refdef.scene.worldentity->model)
3293 r_refdef.scene.worldmodel->DrawShadowMap(r_shadow_shadowmapside, r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, surfacesides, rsurface.rtlight->cached_cullmins, rsurface.rtlight->cached_cullmaxs);
3295 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3298 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3300 qboolean zpass = false;
3303 int surfacelistindex;
3304 msurface_t *surface;
3306 RSurf_ActiveWorldEntity();
3308 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3311 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3313 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3314 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3316 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3317 for (;mesh;mesh = mesh->next)
3319 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3320 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3321 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3323 // increment stencil if frontface is infront of depthbuffer
3324 GL_CullFace(r_refdef.view.cullface_back);
3325 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3326 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3327 // decrement stencil if backface is infront of depthbuffer
3328 GL_CullFace(r_refdef.view.cullface_front);
3329 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3331 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3333 // decrement stencil if backface is behind depthbuffer
3334 GL_CullFace(r_refdef.view.cullface_front);
3335 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3336 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3337 // increment stencil if frontface is behind depthbuffer
3338 GL_CullFace(r_refdef.view.cullface_back);
3339 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3341 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3345 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3347 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3348 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3349 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3351 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3352 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3353 if (CHECKPVSBIT(trispvs, t))
3354 shadowmarklist[numshadowmark++] = t;
3356 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);
3358 else if (numsurfaces)
3359 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight->cached_cullmins, rsurface.rtlight->cached_cullmaxs);
3361 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3364 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3366 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3367 vec_t relativeshadowradius;
3368 RSurf_ActiveModelEntity(ent, false, false, false);
3369 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3370 // we need to re-init the shader for each entity because the matrix changed
3371 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3372 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3373 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3374 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3375 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3376 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3377 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3378 switch (r_shadow_rendermode)
3380 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3381 case R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE:
3382 case R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE:
3383 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3386 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3389 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3392 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3394 // set up properties for rendering light onto this entity
3395 RSurf_ActiveModelEntity(ent, true, true, false);
3396 GL_AlphaTest(false);
3397 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3398 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3399 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3400 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3403 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3405 if (!r_refdef.scene.worldmodel->DrawLight)
3408 // set up properties for rendering light onto this entity
3409 RSurf_ActiveWorldEntity();
3410 GL_AlphaTest(false);
3411 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3412 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3413 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3414 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3416 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3418 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3421 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3423 dp_model_t *model = ent->model;
3424 if (!model->DrawLight)
3427 R_Shadow_SetupEntityLight(ent);
3429 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3431 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3434 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3438 int numleafs, numsurfaces;
3439 int *leaflist, *surfacelist;
3440 unsigned char *leafpvs;
3441 unsigned char *shadowtrispvs;
3442 unsigned char *lighttrispvs;
3443 //unsigned char *surfacesides;
3444 int numlightentities;
3445 int numlightentities_noselfshadow;
3446 int numshadowentities;
3447 int numshadowentities_noselfshadow;
3448 static entity_render_t *lightentities[MAX_EDICTS];
3449 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3450 static entity_render_t *shadowentities[MAX_EDICTS];
3451 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3453 rtlight->draw = false;
3455 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3456 // skip lights that are basically invisible (color 0 0 0)
3457 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3460 // loading is done before visibility checks because loading should happen
3461 // all at once at the start of a level, not when it stalls gameplay.
3462 // (especially important to benchmarks)
3464 if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3466 if (rtlight->compiled)
3467 R_RTLight_Uncompile(rtlight);
3468 R_RTLight_Compile(rtlight);
3472 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3474 // look up the light style value at this time
3475 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3476 VectorScale(rtlight->color, f, rtlight->currentcolor);
3478 if (rtlight->selected)
3480 f = 2 + sin(realtime * M_PI * 4.0);
3481 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3485 // if lightstyle is currently off, don't draw the light
3486 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3489 // if the light box is offscreen, skip it
3490 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3493 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3494 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3496 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3498 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3500 // compiled light, world available and can receive realtime lighting
3501 // retrieve leaf information
3502 numleafs = rtlight->static_numleafs;
3503 leaflist = rtlight->static_leaflist;
3504 leafpvs = rtlight->static_leafpvs;
3505 numsurfaces = rtlight->static_numsurfaces;
3506 surfacelist = rtlight->static_surfacelist;
3507 //surfacesides = NULL;
3508 shadowtrispvs = rtlight->static_shadowtrispvs;
3509 lighttrispvs = rtlight->static_lighttrispvs;
3511 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3513 // dynamic light, world available and can receive realtime lighting
3514 // calculate lit surfaces and leafs
3515 r_refdef.scene.worldmodel->GetLightInfo(r_refdef.scene.worldentity, rtlight->shadoworigin, rtlight->radius, rtlight->cached_cullmins, rtlight->cached_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, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes);
3516 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3517 leaflist = r_shadow_buffer_leaflist;
3518 leafpvs = r_shadow_buffer_leafpvs;
3519 surfacelist = r_shadow_buffer_surfacelist;
3520 //surfacesides = r_shadow_buffer_surfacesides;
3521 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3522 lighttrispvs = r_shadow_buffer_lighttrispvs;
3523 // if the reduced leaf bounds are offscreen, skip it
3524 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3535 //surfacesides = NULL;
3536 shadowtrispvs = NULL;
3537 lighttrispvs = NULL;
3539 // check if light is illuminating any visible leafs
3542 for (i = 0;i < numleafs;i++)
3543 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3549 // make a list of lit entities and shadow casting entities
3550 numlightentities = 0;
3551 numlightentities_noselfshadow = 0;
3552 numshadowentities = 0;
3553 numshadowentities_noselfshadow = 0;
3555 // add dynamic entities that are lit by the light
3556 for (i = 0;i < r_refdef.scene.numentities;i++)
3559 entity_render_t *ent = r_refdef.scene.entities[i];
3561 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3563 // skip the object entirely if it is not within the valid
3564 // shadow-casting region (which includes the lit region)
3565 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3567 if (!(model = ent->model))
3569 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3571 // this entity wants to receive light, is visible, and is
3572 // inside the light box
3573 // TODO: check if the surfaces in the model can receive light
3574 // so now check if it's in a leaf seen by the light
3575 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))
3577 if (ent->flags & RENDER_NOSELFSHADOW)
3578 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3580 lightentities[numlightentities++] = ent;
3581 // since it is lit, it probably also casts a shadow...
3582 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3583 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3584 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3586 // note: exterior models without the RENDER_NOSELFSHADOW
3587 // flag still create a RENDER_NOSELFSHADOW shadow but
3588 // are lit normally, this means that they are
3589 // self-shadowing but do not shadow other
3590 // RENDER_NOSELFSHADOW entities such as the gun
3591 // (very weird, but keeps the player shadow off the gun)
3592 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3593 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3595 shadowentities[numshadowentities++] = ent;
3598 else if (ent->flags & RENDER_SHADOW)
3600 // this entity is not receiving light, but may still need to
3602 // TODO: check if the surfaces in the model can cast shadow
3603 // now check if it is in a leaf seen by the light
3604 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))
3606 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3607 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3608 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3610 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3611 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3613 shadowentities[numshadowentities++] = ent;
3618 // return if there's nothing at all to light
3619 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3622 // count this light in the r_speeds
3623 r_refdef.stats.lights++;
3625 // flag it as worth drawing later
3626 rtlight->draw = true;
3628 // cache all the animated entities that cast a shadow but are not visible
3629 for (i = 0;i < numshadowentities;i++)
3630 if (!shadowentities[i]->animcache_vertex3f)
3631 R_AnimCache_GetEntity(shadowentities[i], false, false);
3632 for (i = 0;i < numshadowentities_noselfshadow;i++)
3633 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3634 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3636 // allocate some temporary memory for rendering this light later in the frame
3637 // reusable buffers need to be copied, static data can be used as-is
3638 rtlight->cached_numlightentities = numlightentities;
3639 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3640 rtlight->cached_numshadowentities = numshadowentities;
3641 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3642 rtlight->cached_numsurfaces = numsurfaces;
3643 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3644 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3645 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3646 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3647 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3649 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3650 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3651 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3652 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3653 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3657 // compiled light data
3658 rtlight->cached_shadowtrispvs = shadowtrispvs;
3659 rtlight->cached_lighttrispvs = lighttrispvs;
3660 rtlight->cached_surfacelist = surfacelist;
3664 void R_Shadow_DrawLight(rtlight_t *rtlight)
3668 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3669 int numlightentities;
3670 int numlightentities_noselfshadow;
3671 int numshadowentities;
3672 int numshadowentities_noselfshadow;
3673 entity_render_t **lightentities;
3674 entity_render_t **lightentities_noselfshadow;
3675 entity_render_t **shadowentities;
3676 entity_render_t **shadowentities_noselfshadow;
3678 static unsigned char entitysides[MAX_EDICTS];
3679 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3680 vec3_t nearestpoint;
3682 qboolean castshadows;
3685 // check if we cached this light this frame (meaning it is worth drawing)
3689 // if R_FrameData_Store ran out of space we skip anything dependent on it
3690 if (r_framedata_failed)
3693 numlightentities = rtlight->cached_numlightentities;
3694 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3695 numshadowentities = rtlight->cached_numshadowentities;
3696 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3697 numsurfaces = rtlight->cached_numsurfaces;
3698 lightentities = rtlight->cached_lightentities;
3699 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3700 shadowentities = rtlight->cached_shadowentities;
3701 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3702 shadowtrispvs = rtlight->cached_shadowtrispvs;
3703 lighttrispvs = rtlight->cached_lighttrispvs;
3704 surfacelist = rtlight->cached_surfacelist;
3706 // set up a scissor rectangle for this light
3707 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3710 // don't let sound skip if going slow
3711 if (r_refdef.scene.extraupdate)
3714 // make this the active rtlight for rendering purposes
3715 R_Shadow_RenderMode_ActiveLight(rtlight);
3717 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3719 // optionally draw visible shape of the shadow volumes
3720 // for performance analysis by level designers
3721 R_Shadow_RenderMode_VisibleShadowVolumes();
3723 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3724 for (i = 0;i < numshadowentities;i++)
3725 R_Shadow_DrawEntityShadow(shadowentities[i]);
3726 for (i = 0;i < numshadowentities_noselfshadow;i++)
3727 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3728 R_Shadow_RenderMode_VisibleLighting(false, false);
3731 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3733 // optionally draw the illuminated areas
3734 // for performance analysis by level designers
3735 R_Shadow_RenderMode_VisibleLighting(false, false);
3737 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3738 for (i = 0;i < numlightentities;i++)
3739 R_Shadow_DrawEntityLight(lightentities[i]);
3740 for (i = 0;i < numlightentities_noselfshadow;i++)
3741 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3744 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3746 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3747 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3748 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3749 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3751 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3752 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3753 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3755 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3761 int receivermask = 0;
3762 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3763 Matrix4x4_Abs(&radiustolight);
3765 r_shadow_shadowmaplod = 0;
3766 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3767 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3768 r_shadow_shadowmaplod = i;
3770 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
3771 size = max(1, r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod);
3773 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3775 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3777 surfacesides = NULL;
3780 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3782 castermask = rtlight->static_shadowmap_casters;
3783 receivermask = rtlight->static_shadowmap_receivers;
3787 surfacesides = r_shadow_buffer_surfacesides;
3788 for(i = 0;i < numsurfaces;i++)
3790 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3791 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3792 castermask |= surfacesides[i];
3793 receivermask |= surfacesides[i];
3797 if (receivermask < 0x3F)
3799 for (i = 0;i < numlightentities;i++)
3800 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3801 if (receivermask < 0x3F)
3802 for(i = 0; i < numlightentities_noselfshadow;i++)
3803 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3806 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3810 for (i = 0;i < numshadowentities;i++)
3811 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3812 for (i = 0;i < numshadowentities_noselfshadow;i++)
3813 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3816 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3818 // render shadow casters into 6 sided depth texture
3819 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3821 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3822 if (! (castermask & (1 << side))) continue;
3824 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3825 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3826 R_Shadow_DrawEntityShadow(shadowentities[i]);
3829 if (numlightentities_noselfshadow)
3831 // render lighting using the depth texture as shadowmap
3832 // draw lighting in the unmasked areas
3833 R_Shadow_RenderMode_Lighting(false, false, true);
3834 for (i = 0;i < numlightentities_noselfshadow;i++)
3835 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3838 // render shadow casters into 6 sided depth texture
3839 if (numshadowentities_noselfshadow)
3841 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3843 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3844 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3845 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3849 // render lighting using the depth texture as shadowmap
3850 // draw lighting in the unmasked areas
3851 R_Shadow_RenderMode_Lighting(false, false, true);
3852 // draw lighting in the unmasked areas
3854 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3855 for (i = 0;i < numlightentities;i++)
3856 R_Shadow_DrawEntityLight(lightentities[i]);
3858 else if (castshadows && vid.stencil)
3860 // draw stencil shadow volumes to mask off pixels that are in shadow
3861 // so that they won't receive lighting
3862 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3863 R_Shadow_ClearStencil();
3866 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3867 for (i = 0;i < numshadowentities;i++)
3868 R_Shadow_DrawEntityShadow(shadowentities[i]);
3870 // draw lighting in the unmasked areas
3871 R_Shadow_RenderMode_Lighting(true, false, false);
3872 for (i = 0;i < numlightentities_noselfshadow;i++)
3873 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3875 for (i = 0;i < numshadowentities_noselfshadow;i++)
3876 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3878 // draw lighting in the unmasked areas
3879 R_Shadow_RenderMode_Lighting(true, false, false);
3881 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3882 for (i = 0;i < numlightentities;i++)
3883 R_Shadow_DrawEntityLight(lightentities[i]);
3887 // draw lighting in the unmasked areas
3888 R_Shadow_RenderMode_Lighting(false, false, false);
3890 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3891 for (i = 0;i < numlightentities;i++)
3892 R_Shadow_DrawEntityLight(lightentities[i]);
3893 for (i = 0;i < numlightentities_noselfshadow;i++)
3894 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3897 if (r_shadow_usingdeferredprepass)
3899 // when rendering deferred lighting, we simply rasterize the box
3900 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3901 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3902 else if (castshadows && vid.stencil)
3903 R_Shadow_RenderMode_DrawDeferredLight(true, false);
3905 R_Shadow_RenderMode_DrawDeferredLight(false, false);
3909 static void R_Shadow_FreeDeferred(void)
3911 if (r_shadow_prepassgeometryfbo)
3912 qglDeleteFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
3913 r_shadow_prepassgeometryfbo = 0;
3915 if (r_shadow_prepasslightingfbo)
3916 qglDeleteFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
3917 r_shadow_prepasslightingfbo = 0;
3919 if (r_shadow_prepassgeometrydepthtexture)
3920 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3921 r_shadow_prepassgeometrydepthtexture = NULL;
3923 if (r_shadow_prepassgeometrynormalmaptexture)
3924 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3925 r_shadow_prepassgeometrynormalmaptexture = NULL;
3927 if (r_shadow_prepasslightingdiffusetexture)
3928 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3929 r_shadow_prepasslightingdiffusetexture = NULL;
3931 if (r_shadow_prepasslightingspeculartexture)
3932 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3933 r_shadow_prepasslightingspeculartexture = NULL;
3936 void R_Shadow_DrawPrepass(void)
3944 entity_render_t *ent;
3946 GL_AlphaTest(false);
3947 R_Mesh_ColorPointer(NULL, 0, 0);
3948 R_Mesh_ResetTextureState();
3950 GL_ColorMask(1,1,1,1);
3951 GL_BlendFunc(GL_ONE, GL_ZERO);
3954 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
3955 qglClearColor(0.5f,0.5f,0.5f,1.0f);CHECKGLERROR
3956 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);CHECKGLERROR
3958 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3959 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3960 if (r_timereport_active)
3961 R_TimeReport("prepassworld");
3963 for (i = 0;i < r_refdef.scene.numentities;i++)
3965 if (!r_refdef.viewcache.entityvisible[i])
3967 ent = r_refdef.scene.entities[i];
3968 if (ent->model && ent->model->DrawPrepass != NULL)
3969 ent->model->DrawPrepass(ent);
3972 if (r_timereport_active)
3973 R_TimeReport("prepassmodels");
3975 GL_DepthMask(false);
3976 GL_ColorMask(1,1,1,1);
3979 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
3980 qglClearColor(0.0f,0.0f,0.0f,0.0f);CHECKGLERROR
3981 GL_Clear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
3982 if (r_refdef.fogenabled)
3983 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
3985 R_Shadow_RenderMode_Begin();
3987 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3988 if (r_shadow_debuglight.integer >= 0)
3990 lightindex = r_shadow_debuglight.integer;
3991 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3992 if (light && (light->flags & flag))
3993 R_Shadow_DrawLight(&light->rtlight);
3997 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3998 for (lightindex = 0;lightindex < range;lightindex++)
4000 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4001 if (light && (light->flags & flag))
4002 R_Shadow_DrawLight(&light->rtlight);
4005 if (r_refdef.scene.rtdlight)
4006 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4007 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4009 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
4010 if (r_refdef.fogenabled)
4011 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
4013 R_Shadow_RenderMode_End();
4015 if (r_timereport_active)
4016 R_TimeReport("prepasslights");
4019 void R_Shadow_DrawLightSprites(void);
4020 void R_Shadow_PrepareLights(void)
4030 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4031 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4032 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4033 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4034 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4035 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4036 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4037 R_Shadow_FreeShadowMaps();
4039 r_shadow_usingshadowmaportho = false;
4041 switch (vid.renderpath)
4043 case RENDERPATH_GL20:
4044 case RENDERPATH_CGGL:
4045 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4047 r_shadow_usingdeferredprepass = false;
4048 if (r_shadow_prepass_width)
4049 R_Shadow_FreeDeferred();
4050 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4054 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4056 R_Shadow_FreeDeferred();
4058 r_shadow_usingdeferredprepass = true;
4059 r_shadow_prepass_width = vid.width;
4060 r_shadow_prepass_height = vid.height;
4061 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4062 r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4063 r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4064 r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4066 // set up the geometry pass fbo (depth + normalmap)
4067 qglGenFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
4068 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
4069 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4070 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrynormalmaptexture), 0);CHECKGLERROR
4071 // render depth into one texture and normalmap into the other
4072 if (qglDrawBuffersARB)
4074 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4075 qglReadBuffer(GL_NONE);CHECKGLERROR
4077 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4078 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4080 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4081 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4082 r_shadow_usingdeferredprepass = false;
4085 // set up the lighting pass fbo (diffuse + specular)
4086 qglGenFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
4087 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
4088 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4089 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingdiffusetexture), 0);CHECKGLERROR
4090 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingspeculartexture), 0);CHECKGLERROR
4091 // render diffuse into one texture and specular into another,
4092 // with depth and normalmap bound as textures,
4093 // with depth bound as attachment as well
4094 if (qglDrawBuffersARB)
4096 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4097 qglReadBuffer(GL_NONE);CHECKGLERROR
4099 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4100 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4102 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4103 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4104 r_shadow_usingdeferredprepass = false;
4108 case RENDERPATH_GL13:
4109 case RENDERPATH_GL11:
4110 r_shadow_usingdeferredprepass = false;
4114 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);
4116 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4117 if (r_shadow_debuglight.integer >= 0)
4119 lightindex = r_shadow_debuglight.integer;
4120 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4121 if (light && (light->flags & flag))
4122 R_Shadow_PrepareLight(&light->rtlight);
4126 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4127 for (lightindex = 0;lightindex < range;lightindex++)
4129 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4130 if (light && (light->flags & flag))
4131 R_Shadow_PrepareLight(&light->rtlight);
4134 if (r_refdef.scene.rtdlight)
4136 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4137 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4139 else if(gl_flashblend.integer)
4141 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4143 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4144 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4145 VectorScale(rtlight->color, f, rtlight->currentcolor);
4149 if (r_editlights.integer)
4150 R_Shadow_DrawLightSprites();
4153 void R_Shadow_DrawLights(void)
4161 R_Shadow_RenderMode_Begin();
4163 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4164 if (r_shadow_debuglight.integer >= 0)
4166 lightindex = r_shadow_debuglight.integer;
4167 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4168 if (light && (light->flags & flag))
4169 R_Shadow_DrawLight(&light->rtlight);
4173 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4174 for (lightindex = 0;lightindex < range;lightindex++)
4176 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4177 if (light && (light->flags & flag))
4178 R_Shadow_DrawLight(&light->rtlight);
4181 if (r_refdef.scene.rtdlight)
4182 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4183 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4185 R_Shadow_RenderMode_End();
4188 extern const float r_screenvertex3f[12];
4189 extern void R_SetupView(qboolean allowwaterclippingplane);
4190 extern void R_ResetViewRendering3D(void);
4191 extern void R_ResetViewRendering2D(void);
4192 extern cvar_t r_shadows;
4193 extern cvar_t r_shadows_darken;
4194 extern cvar_t r_shadows_drawafterrtlighting;
4195 extern cvar_t r_shadows_castfrombmodels;
4196 extern cvar_t r_shadows_throwdistance;
4197 extern cvar_t r_shadows_throwdirection;
4199 void R_DrawModelShadowMaps(void)
4202 float relativethrowdistance, scale, size, nearclip, farclip, dot1, dot2;
4203 entity_render_t *ent;
4204 vec3_t relativelightorigin;
4205 vec3_t relativelightdirection;
4206 vec3_t relativeshadowmins, relativeshadowmaxs;
4207 vec3_t shadowdir, shadowforward;
4209 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix;
4210 r_viewport_t viewport;
4213 if (!r_refdef.scene.numentities)
4216 switch (r_shadow_shadowmode)
4218 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4219 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4226 R_ResetViewRendering3D();
4227 R_Shadow_RenderMode_Begin();
4228 R_Shadow_RenderMode_ActiveLight(NULL);
4230 switch (r_shadow_shadowmode)
4232 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4233 if (!r_shadow_shadowmap2dtexture)
4234 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4235 fbo = r_shadow_fbo2d;
4236 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4237 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4238 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4240 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4241 if (!r_shadow_shadowmaprectangletexture)
4242 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4243 fbo = r_shadow_fborectangle;
4244 r_shadow_shadowmap_texturescale[0] = 1.0f;
4245 r_shadow_shadowmap_texturescale[1] = 1.0f;
4246 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
4252 size = 2*r_shadow_shadowmapmaxsize;
4254 r_shadow_shadowmap_parameters[0] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4255 r_shadow_shadowmap_parameters[1] = 1.0f;
4256 r_shadow_shadowmap_parameters[2] = size;
4257 r_shadow_shadowmap_parameters[3] = size;
4259 scale = r_shadow_shadowmapping_precision.value;
4260 nearclip = -r_shadows_throwdistance.value;
4261 farclip = r_shadows_throwdistance.value;
4262 Math_atov(r_shadows_throwdirection.string, shadowdir);
4263 VectorNormalize(shadowdir);
4264 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4265 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4266 if (fabs(dot1) <= fabs(dot2))
4267 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4269 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4270 VectorNormalize(shadowforward);
4271 VectorM(scale, shadowforward, &m[0]);
4272 m[3] = fabs(dot1) * 0.5f * size - DotProduct(r_refdef.view.origin, &m[0]);
4273 CrossProduct(shadowdir, shadowforward, &m[4]);
4274 VectorM(scale, &m[4], &m[4]);
4275 m[7] = 0.5f * size - DotProduct(r_refdef.view.origin, &m[4]);
4276 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4277 m[11] = 0.5f - DotProduct(r_refdef.view.origin, &m[8]);
4278 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4279 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4280 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, size, size, 0, 0, -1, NULL);
4283 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
4284 R_SetupShader_ShowDepth();
4286 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
4287 R_SetupShader_DepthOrShadow();
4290 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4293 R_SetViewport(&viewport);
4294 GL_Scissor(viewport.x, viewport.y, viewport.width + r_shadow_shadowmapborder, viewport.height + r_shadow_shadowmapborder);
4297 qglClearColor(1,1,1,1);
4298 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
4300 GL_Clear(GL_DEPTH_BUFFER_BIT);
4302 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4305 for (i = 0;i < r_refdef.scene.numentities;i++)
4307 ent = r_refdef.scene.entities[i];
4309 // cast shadows from anything of the map (submodels are optional)
4310 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4312 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4313 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4314 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4315 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4316 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4317 RSurf_ActiveModelEntity(ent, false, false, false);
4318 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4319 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4323 R_Shadow_RenderMode_End();
4325 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4326 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4327 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &shadowmatrix, &invmvpmatrix);
4329 r_shadow_usingshadowmaportho = true;
4330 switch (r_shadow_shadowmode)
4332 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4333 r_shadow_usingshadowmap2d = true;
4335 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4336 r_shadow_usingshadowmaprect = true;
4343 void R_DrawModelShadows(void)
4346 float relativethrowdistance;
4347 entity_render_t *ent;
4348 vec3_t relativelightorigin;
4349 vec3_t relativelightdirection;
4350 vec3_t relativeshadowmins, relativeshadowmaxs;
4351 vec3_t tmp, shadowdir;
4353 if (!r_refdef.scene.numentities || !vid.stencil || r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL)
4357 R_ResetViewRendering3D();
4358 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4359 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4360 R_Shadow_RenderMode_Begin();
4361 R_Shadow_RenderMode_ActiveLight(NULL);
4362 r_shadow_lightscissor[0] = r_refdef.view.x;
4363 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4364 r_shadow_lightscissor[2] = r_refdef.view.width;
4365 r_shadow_lightscissor[3] = r_refdef.view.height;
4366 R_Shadow_RenderMode_StencilShadowVolumes(false);
4369 if (r_shadows.integer == 2)
4371 Math_atov(r_shadows_throwdirection.string, shadowdir);
4372 VectorNormalize(shadowdir);
4375 R_Shadow_ClearStencil();
4377 for (i = 0;i < r_refdef.scene.numentities;i++)
4379 ent = r_refdef.scene.entities[i];
4381 // cast shadows from anything of the map (submodels are optional)
4382 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4384 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4385 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4386 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4387 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4388 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4391 if(ent->entitynumber != 0)
4393 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4394 int entnum, entnum2, recursion;
4395 entnum = entnum2 = ent->entitynumber;
4396 for(recursion = 32; recursion > 0; --recursion)
4398 entnum2 = cl.entities[entnum].state_current.tagentity;
4399 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4404 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4406 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4407 // transform into modelspace of OUR entity
4408 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4409 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4412 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4415 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4418 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4419 RSurf_ActiveModelEntity(ent, false, false, false);
4420 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4421 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4425 // not really the right mode, but this will disable any silly stencil features
4426 R_Shadow_RenderMode_End();
4428 // set up ortho view for rendering this pass
4429 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4430 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4431 //GL_ScissorTest(true);
4432 //R_EntityMatrix(&identitymatrix);
4433 //R_Mesh_ResetTextureState();
4434 R_ResetViewRendering2D();
4435 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4436 R_Mesh_ColorPointer(NULL, 0, 0);
4437 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4439 // set up a darkening blend on shadowed areas
4440 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4441 //GL_DepthRange(0, 1);
4442 //GL_DepthTest(false);
4443 //GL_DepthMask(false);
4444 //GL_PolygonOffset(0, 0);CHECKGLERROR
4445 GL_Color(0, 0, 0, r_shadows_darken.value);
4446 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4447 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4448 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4449 qglStencilMask(255);CHECKGLERROR
4450 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4451 qglStencilFunc(GL_NOTEQUAL, 128, 255);CHECKGLERROR
4453 // apply the blend to the shadowed areas
4454 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4456 // restore the viewport
4457 R_SetViewport(&r_refdef.view.viewport);
4459 // restore other state to normal
4460 //R_Shadow_RenderMode_End();
4463 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4466 vec3_t centerorigin;
4468 // if it's too close, skip it
4469 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4471 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4474 if (usequery && r_numqueries + 2 <= r_maxqueries)
4476 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4477 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4478 // we count potential samples in the middle of the screen, we count actual samples at the light location, this allows counting potential samples of off-screen lights
4479 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4482 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use qglDepthFunc instead
4483 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4484 qglDepthFunc(GL_ALWAYS);
4485 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4486 R_Mesh_VertexPointer(vertex3f, 0, 0);
4487 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4488 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4489 qglDepthFunc(GL_LEQUAL);
4490 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4491 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4492 R_Mesh_VertexPointer(vertex3f, 0, 0);
4493 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4494 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4497 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4500 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4502 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4505 GLint allpixels = 0, visiblepixels = 0;
4506 // now we have to check the query result
4507 if (rtlight->corona_queryindex_visiblepixels)
4510 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4511 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4513 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4514 if (visiblepixels < 1 || allpixels < 1)
4516 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4517 cscale *= rtlight->corona_visibility;
4521 // FIXME: these traces should scan all render entities instead of cl.world
4522 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4525 VectorScale(rtlight->currentcolor, cscale, color);
4526 if (VectorLength(color) > (1.0f / 256.0f))
4529 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4532 VectorNegate(color, color);
4533 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4535 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4536 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, RENDER_NODEPTHTEST, 0, color[0], color[1], color[2], 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4537 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4539 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4543 void R_Shadow_DrawCoronas(void)
4551 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4553 if (r_waterstate.renderingscene)
4555 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4556 R_EntityMatrix(&identitymatrix);
4558 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4560 // check occlusion of coronas
4561 // use GL_ARB_occlusion_query if available
4562 // otherwise use raytraces
4564 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4567 GL_ColorMask(0,0,0,0);
4568 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4569 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4572 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4573 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4575 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4578 RSurf_ActiveWorldEntity();
4579 GL_BlendFunc(GL_ONE, GL_ZERO);
4580 GL_CullFace(GL_NONE);
4581 GL_DepthMask(false);
4582 GL_DepthRange(0, 1);
4583 GL_PolygonOffset(0, 0);
4585 R_Mesh_ColorPointer(NULL, 0, 0);
4586 R_Mesh_ResetTextureState();
4587 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4589 for (lightindex = 0;lightindex < range;lightindex++)
4591 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4594 rtlight = &light->rtlight;
4595 rtlight->corona_visibility = 0;
4596 rtlight->corona_queryindex_visiblepixels = 0;
4597 rtlight->corona_queryindex_allpixels = 0;
4598 if (!(rtlight->flags & flag))
4600 if (rtlight->corona <= 0)
4602 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4604 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4606 for (i = 0;i < r_refdef.scene.numlights;i++)
4608 rtlight = r_refdef.scene.lights[i];
4609 rtlight->corona_visibility = 0;
4610 rtlight->corona_queryindex_visiblepixels = 0;
4611 rtlight->corona_queryindex_allpixels = 0;
4612 if (!(rtlight->flags & flag))
4614 if (rtlight->corona <= 0)
4616 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4619 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4621 // now draw the coronas using the query data for intensity info
4622 for (lightindex = 0;lightindex < range;lightindex++)
4624 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4627 rtlight = &light->rtlight;
4628 if (rtlight->corona_visibility <= 0)
4630 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4632 for (i = 0;i < r_refdef.scene.numlights;i++)
4634 rtlight = r_refdef.scene.lights[i];
4635 if (rtlight->corona_visibility <= 0)
4637 if (gl_flashblend.integer)
4638 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4640 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4646 dlight_t *R_Shadow_NewWorldLight(void)
4648 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4651 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)
4654 // validate parameters
4655 if (style < 0 || style >= MAX_LIGHTSTYLES)
4657 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4663 // copy to light properties
4664 VectorCopy(origin, light->origin);
4665 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4666 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4667 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4669 light->color[0] = max(color[0], 0);
4670 light->color[1] = max(color[1], 0);
4671 light->color[2] = max(color[2], 0);
4673 light->color[0] = color[0];
4674 light->color[1] = color[1];
4675 light->color[2] = color[2];
4676 light->radius = max(radius, 0);
4677 light->style = style;
4678 light->shadow = shadowenable;
4679 light->corona = corona;
4680 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4681 light->coronasizescale = coronasizescale;
4682 light->ambientscale = ambientscale;
4683 light->diffusescale = diffusescale;
4684 light->specularscale = specularscale;
4685 light->flags = flags;
4687 // update renderable light data
4688 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4689 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);
4692 void R_Shadow_FreeWorldLight(dlight_t *light)
4694 if (r_shadow_selectedlight == light)
4695 r_shadow_selectedlight = NULL;
4696 R_RTLight_Uncompile(&light->rtlight);
4697 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4700 void R_Shadow_ClearWorldLights(void)
4704 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4705 for (lightindex = 0;lightindex < range;lightindex++)
4707 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4709 R_Shadow_FreeWorldLight(light);
4711 r_shadow_selectedlight = NULL;
4714 void R_Shadow_SelectLight(dlight_t *light)
4716 if (r_shadow_selectedlight)
4717 r_shadow_selectedlight->selected = false;
4718 r_shadow_selectedlight = light;
4719 if (r_shadow_selectedlight)
4720 r_shadow_selectedlight->selected = true;
4723 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4725 // this is never batched (there can be only one)
4727 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4728 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4729 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4732 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4737 skinframe_t *skinframe;
4740 // this is never batched (due to the ent parameter changing every time)
4741 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4742 const dlight_t *light = (dlight_t *)ent;
4745 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4748 VectorScale(light->color, intensity, spritecolor);
4749 if (VectorLength(spritecolor) < 0.1732f)
4750 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4751 if (VectorLength(spritecolor) > 1.0f)
4752 VectorNormalize(spritecolor);
4754 // draw light sprite
4755 if (light->cubemapname[0] && !light->shadow)
4756 skinframe = r_editlights_sprcubemapnoshadowlight;
4757 else if (light->cubemapname[0])
4758 skinframe = r_editlights_sprcubemaplight;
4759 else if (!light->shadow)
4760 skinframe = r_editlights_sprnoshadowlight;
4762 skinframe = r_editlights_sprlight;
4764 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, spritecolor[0], spritecolor[1], spritecolor[2], 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4765 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4767 // draw selection sprite if light is selected
4768 if (light->selected)
4770 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4771 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4772 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4776 void R_Shadow_DrawLightSprites(void)
4780 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4781 for (lightindex = 0;lightindex < range;lightindex++)
4783 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4785 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4787 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4790 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4795 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4796 if (lightindex >= range)
4798 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4801 rtlight = &light->rtlight;
4802 //if (!(rtlight->flags & flag))
4804 VectorCopy(rtlight->shadoworigin, origin);
4805 *radius = rtlight->radius;
4806 VectorCopy(rtlight->color, color);
4810 void R_Shadow_SelectLightInView(void)
4812 float bestrating, rating, temp[3];
4816 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4819 for (lightindex = 0;lightindex < range;lightindex++)
4821 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4824 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4825 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4828 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4829 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4831 bestrating = rating;
4836 R_Shadow_SelectLight(best);
4839 void R_Shadow_LoadWorldLights(void)
4841 int n, a, style, shadow, flags;
4842 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4843 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4844 if (cl.worldmodel == NULL)
4846 Con_Print("No map loaded.\n");
4849 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4850 strlcat (name, ".rtlights", sizeof (name));
4851 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4861 for (;COM_Parse(t, true) && strcmp(
4862 if (COM_Parse(t, true))
4864 if (com_token[0] == '!')
4867 origin[0] = atof(com_token+1);
4870 origin[0] = atof(com_token);
4875 while (*s && *s != '\n' && *s != '\r')
4881 // check for modifier flags
4888 #if _MSC_VER >= 1400
4889 #define sscanf sscanf_s
4891 cubemapname[sizeof(cubemapname)-1] = 0;
4892 #if MAX_QPATH != 128
4893 #error update this code if MAX_QPATH changes
4895 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
4896 #if _MSC_VER >= 1400
4897 , sizeof(cubemapname)
4899 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4902 flags = LIGHTFLAG_REALTIMEMODE;
4910 coronasizescale = 0.25f;
4912 VectorClear(angles);
4915 if (a < 9 || !strcmp(cubemapname, "\"\""))
4917 // remove quotes on cubemapname
4918 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4921 namelen = strlen(cubemapname) - 2;
4922 memmove(cubemapname, cubemapname + 1, namelen);
4923 cubemapname[namelen] = '\0';
4927 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);
4930 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4938 Con_Printf("invalid rtlights file \"%s\"\n", name);
4939 Mem_Free(lightsstring);
4943 void R_Shadow_SaveWorldLights(void)
4947 size_t bufchars, bufmaxchars;
4949 char name[MAX_QPATH];
4950 char line[MAX_INPUTLINE];
4951 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4952 // I hate lines which are 3 times my screen size :( --blub
4955 if (cl.worldmodel == NULL)
4957 Con_Print("No map loaded.\n");
4960 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4961 strlcat (name, ".rtlights", sizeof (name));
4962 bufchars = bufmaxchars = 0;
4964 for (lightindex = 0;lightindex < range;lightindex++)
4966 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4969 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4970 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);
4971 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4972 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]);
4974 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);
4975 if (bufchars + strlen(line) > bufmaxchars)
4977 bufmaxchars = bufchars + strlen(line) + 2048;
4979 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4983 memcpy(buf, oldbuf, bufchars);
4989 memcpy(buf + bufchars, line, strlen(line));
4990 bufchars += strlen(line);
4994 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4999 void R_Shadow_LoadLightsFile(void)
5002 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5003 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5004 if (cl.worldmodel == NULL)
5006 Con_Print("No map loaded.\n");
5009 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5010 strlcat (name, ".lights", sizeof (name));
5011 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5019 while (*s && *s != '\n' && *s != '\r')
5025 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);
5029 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);
5032 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5033 radius = bound(15, radius, 4096);
5034 VectorScale(color, (2.0f / (8388608.0f)), color);
5035 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5043 Con_Printf("invalid lights file \"%s\"\n", name);
5044 Mem_Free(lightsstring);
5048 // tyrlite/hmap2 light types in the delay field
5049 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5051 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5063 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5064 char key[256], value[MAX_INPUTLINE];
5066 if (cl.worldmodel == NULL)
5068 Con_Print("No map loaded.\n");
5071 // try to load a .ent file first
5072 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
5073 strlcat (key, ".ent", sizeof (key));
5074 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5075 // and if that is not found, fall back to the bsp file entity string
5077 data = cl.worldmodel->brush.entities;
5080 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5082 type = LIGHTTYPE_MINUSX;
5083 origin[0] = origin[1] = origin[2] = 0;
5084 originhack[0] = originhack[1] = originhack[2] = 0;
5085 angles[0] = angles[1] = angles[2] = 0;
5086 color[0] = color[1] = color[2] = 1;
5087 light[0] = light[1] = light[2] = 1;light[3] = 300;
5088 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5098 if (!COM_ParseToken_Simple(&data, false, false))
5100 if (com_token[0] == '}')
5101 break; // end of entity
5102 if (com_token[0] == '_')
5103 strlcpy(key, com_token + 1, sizeof(key));
5105 strlcpy(key, com_token, sizeof(key));
5106 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5107 key[strlen(key)-1] = 0;
5108 if (!COM_ParseToken_Simple(&data, false, false))
5110 strlcpy(value, com_token, sizeof(value));
5112 // now that we have the key pair worked out...
5113 if (!strcmp("light", key))
5115 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5119 light[0] = vec[0] * (1.0f / 256.0f);
5120 light[1] = vec[0] * (1.0f / 256.0f);
5121 light[2] = vec[0] * (1.0f / 256.0f);
5127 light[0] = vec[0] * (1.0f / 255.0f);
5128 light[1] = vec[1] * (1.0f / 255.0f);
5129 light[2] = vec[2] * (1.0f / 255.0f);
5133 else if (!strcmp("delay", key))
5135 else if (!strcmp("origin", key))
5136 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5137 else if (!strcmp("angle", key))
5138 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5139 else if (!strcmp("angles", key))
5140 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5141 else if (!strcmp("color", key))
5142 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5143 else if (!strcmp("wait", key))
5144 fadescale = atof(value);
5145 else if (!strcmp("classname", key))
5147 if (!strncmp(value, "light", 5))
5150 if (!strcmp(value, "light_fluoro"))
5155 overridecolor[0] = 1;
5156 overridecolor[1] = 1;
5157 overridecolor[2] = 1;
5159 if (!strcmp(value, "light_fluorospark"))
5164 overridecolor[0] = 1;
5165 overridecolor[1] = 1;
5166 overridecolor[2] = 1;
5168 if (!strcmp(value, "light_globe"))
5173 overridecolor[0] = 1;
5174 overridecolor[1] = 0.8;
5175 overridecolor[2] = 0.4;
5177 if (!strcmp(value, "light_flame_large_yellow"))
5182 overridecolor[0] = 1;
5183 overridecolor[1] = 0.5;
5184 overridecolor[2] = 0.1;
5186 if (!strcmp(value, "light_flame_small_yellow"))
5191 overridecolor[0] = 1;
5192 overridecolor[1] = 0.5;
5193 overridecolor[2] = 0.1;
5195 if (!strcmp(value, "light_torch_small_white"))
5200 overridecolor[0] = 1;
5201 overridecolor[1] = 0.5;
5202 overridecolor[2] = 0.1;
5204 if (!strcmp(value, "light_torch_small_walltorch"))
5209 overridecolor[0] = 1;
5210 overridecolor[1] = 0.5;
5211 overridecolor[2] = 0.1;
5215 else if (!strcmp("style", key))
5216 style = atoi(value);
5217 else if (!strcmp("skin", key))
5218 skin = (int)atof(value);
5219 else if (!strcmp("pflags", key))
5220 pflags = (int)atof(value);
5221 //else if (!strcmp("effects", key))
5222 // effects = (int)atof(value);
5223 else if (cl.worldmodel->type == mod_brushq3)
5225 if (!strcmp("scale", key))
5226 lightscale = atof(value);
5227 if (!strcmp("fade", key))
5228 fadescale = atof(value);
5233 if (lightscale <= 0)
5237 if (color[0] == color[1] && color[0] == color[2])
5239 color[0] *= overridecolor[0];
5240 color[1] *= overridecolor[1];
5241 color[2] *= overridecolor[2];
5243 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5244 color[0] = color[0] * light[0];
5245 color[1] = color[1] * light[1];
5246 color[2] = color[2] * light[2];
5249 case LIGHTTYPE_MINUSX:
5251 case LIGHTTYPE_RECIPX:
5253 VectorScale(color, (1.0f / 16.0f), color);
5255 case LIGHTTYPE_RECIPXX:
5257 VectorScale(color, (1.0f / 16.0f), color);
5260 case LIGHTTYPE_NONE:
5264 case LIGHTTYPE_MINUSXX:
5267 VectorAdd(origin, originhack, origin);
5269 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);
5272 Mem_Free(entfiledata);
5276 void R_Shadow_SetCursorLocationForView(void)
5279 vec3_t dest, endpos;
5281 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5282 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5283 if (trace.fraction < 1)
5285 dist = trace.fraction * r_editlights_cursordistance.value;
5286 push = r_editlights_cursorpushback.value;
5290 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5291 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5295 VectorClear( endpos );
5297 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5298 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5299 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5302 void R_Shadow_UpdateWorldLightSelection(void)
5304 if (r_editlights.integer)
5306 R_Shadow_SetCursorLocationForView();
5307 R_Shadow_SelectLightInView();
5310 R_Shadow_SelectLight(NULL);
5313 void R_Shadow_EditLights_Clear_f(void)
5315 R_Shadow_ClearWorldLights();
5318 void R_Shadow_EditLights_Reload_f(void)
5322 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5323 R_Shadow_ClearWorldLights();
5324 R_Shadow_LoadWorldLights();
5325 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5327 R_Shadow_LoadLightsFile();
5328 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5329 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5333 void R_Shadow_EditLights_Save_f(void)
5337 R_Shadow_SaveWorldLights();
5340 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5342 R_Shadow_ClearWorldLights();
5343 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5346 void R_Shadow_EditLights_ImportLightsFile_f(void)
5348 R_Shadow_ClearWorldLights();
5349 R_Shadow_LoadLightsFile();
5352 void R_Shadow_EditLights_Spawn_f(void)
5355 if (!r_editlights.integer)
5357 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5360 if (Cmd_Argc() != 1)
5362 Con_Print("r_editlights_spawn does not take parameters\n");
5365 color[0] = color[1] = color[2] = 1;
5366 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5369 void R_Shadow_EditLights_Edit_f(void)
5371 vec3_t origin, angles, color;
5372 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5373 int style, shadows, flags, normalmode, realtimemode;
5374 char cubemapname[MAX_INPUTLINE];
5375 if (!r_editlights.integer)
5377 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5380 if (!r_shadow_selectedlight)
5382 Con_Print("No selected light.\n");
5385 VectorCopy(r_shadow_selectedlight->origin, origin);
5386 VectorCopy(r_shadow_selectedlight->angles, angles);
5387 VectorCopy(r_shadow_selectedlight->color, color);
5388 radius = r_shadow_selectedlight->radius;
5389 style = r_shadow_selectedlight->style;
5390 if (r_shadow_selectedlight->cubemapname)
5391 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5394 shadows = r_shadow_selectedlight->shadow;
5395 corona = r_shadow_selectedlight->corona;
5396 coronasizescale = r_shadow_selectedlight->coronasizescale;
5397 ambientscale = r_shadow_selectedlight->ambientscale;
5398 diffusescale = r_shadow_selectedlight->diffusescale;
5399 specularscale = r_shadow_selectedlight->specularscale;
5400 flags = r_shadow_selectedlight->flags;
5401 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5402 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5403 if (!strcmp(Cmd_Argv(1), "origin"))
5405 if (Cmd_Argc() != 5)
5407 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5410 origin[0] = atof(Cmd_Argv(2));
5411 origin[1] = atof(Cmd_Argv(3));
5412 origin[2] = atof(Cmd_Argv(4));
5414 else if (!strcmp(Cmd_Argv(1), "originx"))
5416 if (Cmd_Argc() != 3)
5418 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5421 origin[0] = atof(Cmd_Argv(2));
5423 else if (!strcmp(Cmd_Argv(1), "originy"))
5425 if (Cmd_Argc() != 3)
5427 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5430 origin[1] = atof(Cmd_Argv(2));
5432 else if (!strcmp(Cmd_Argv(1), "originz"))
5434 if (Cmd_Argc() != 3)
5436 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5439 origin[2] = atof(Cmd_Argv(2));
5441 else if (!strcmp(Cmd_Argv(1), "move"))
5443 if (Cmd_Argc() != 5)
5445 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5448 origin[0] += atof(Cmd_Argv(2));
5449 origin[1] += atof(Cmd_Argv(3));
5450 origin[2] += atof(Cmd_Argv(4));
5452 else if (!strcmp(Cmd_Argv(1), "movex"))
5454 if (Cmd_Argc() != 3)
5456 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5459 origin[0] += atof(Cmd_Argv(2));
5461 else if (!strcmp(Cmd_Argv(1), "movey"))
5463 if (Cmd_Argc() != 3)
5465 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5468 origin[1] += atof(Cmd_Argv(2));
5470 else if (!strcmp(Cmd_Argv(1), "movez"))
5472 if (Cmd_Argc() != 3)
5474 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5477 origin[2] += atof(Cmd_Argv(2));
5479 else if (!strcmp(Cmd_Argv(1), "angles"))
5481 if (Cmd_Argc() != 5)
5483 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5486 angles[0] = atof(Cmd_Argv(2));
5487 angles[1] = atof(Cmd_Argv(3));
5488 angles[2] = atof(Cmd_Argv(4));
5490 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5492 if (Cmd_Argc() != 3)
5494 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5497 angles[0] = atof(Cmd_Argv(2));
5499 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5501 if (Cmd_Argc() != 3)
5503 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5506 angles[1] = atof(Cmd_Argv(2));
5508 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5510 if (Cmd_Argc() != 3)
5512 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5515 angles[2] = atof(Cmd_Argv(2));
5517 else if (!strcmp(Cmd_Argv(1), "color"))
5519 if (Cmd_Argc() != 5)
5521 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5524 color[0] = atof(Cmd_Argv(2));
5525 color[1] = atof(Cmd_Argv(3));
5526 color[2] = atof(Cmd_Argv(4));
5528 else if (!strcmp(Cmd_Argv(1), "radius"))
5530 if (Cmd_Argc() != 3)
5532 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5535 radius = atof(Cmd_Argv(2));
5537 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5539 if (Cmd_Argc() == 3)
5541 double scale = atof(Cmd_Argv(2));
5548 if (Cmd_Argc() != 5)
5550 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5553 color[0] *= atof(Cmd_Argv(2));
5554 color[1] *= atof(Cmd_Argv(3));
5555 color[2] *= atof(Cmd_Argv(4));
5558 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5560 if (Cmd_Argc() != 3)
5562 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5565 radius *= atof(Cmd_Argv(2));
5567 else if (!strcmp(Cmd_Argv(1), "style"))
5569 if (Cmd_Argc() != 3)
5571 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5574 style = atoi(Cmd_Argv(2));
5576 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5580 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5583 if (Cmd_Argc() == 3)
5584 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5588 else if (!strcmp(Cmd_Argv(1), "shadows"))
5590 if (Cmd_Argc() != 3)
5592 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5595 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5597 else if (!strcmp(Cmd_Argv(1), "corona"))
5599 if (Cmd_Argc() != 3)
5601 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5604 corona = atof(Cmd_Argv(2));
5606 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5608 if (Cmd_Argc() != 3)
5610 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5613 coronasizescale = atof(Cmd_Argv(2));
5615 else if (!strcmp(Cmd_Argv(1), "ambient"))
5617 if (Cmd_Argc() != 3)
5619 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5622 ambientscale = atof(Cmd_Argv(2));
5624 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5626 if (Cmd_Argc() != 3)
5628 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5631 diffusescale = atof(Cmd_Argv(2));
5633 else if (!strcmp(Cmd_Argv(1), "specular"))
5635 if (Cmd_Argc() != 3)
5637 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5640 specularscale = atof(Cmd_Argv(2));
5642 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5644 if (Cmd_Argc() != 3)
5646 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5649 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5651 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5653 if (Cmd_Argc() != 3)
5655 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5658 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5662 Con_Print("usage: r_editlights_edit [property] [value]\n");
5663 Con_Print("Selected light's properties:\n");
5664 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5665 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5666 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5667 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5668 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5669 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5670 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5671 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5672 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5673 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5674 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5675 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5676 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5677 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5680 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5681 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5684 void R_Shadow_EditLights_EditAll_f(void)
5690 if (!r_editlights.integer)
5692 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5696 // EditLights doesn't seem to have a "remove" command or something so:
5697 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5698 for (lightindex = 0;lightindex < range;lightindex++)
5700 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5703 R_Shadow_SelectLight(light);
5704 R_Shadow_EditLights_Edit_f();
5708 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5710 int lightnumber, lightcount;
5711 size_t lightindex, range;
5715 if (!r_editlights.integer)
5717 x = vid_conwidth.value - 240;
5719 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5722 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5723 for (lightindex = 0;lightindex < range;lightindex++)
5725 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5728 if (light == r_shadow_selectedlight)
5729 lightnumber = lightindex;
5732 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, FONT_DEFAULT);y += 8;
5733 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, FONT_DEFAULT);y += 8;
5735 if (r_shadow_selectedlight == NULL)
5737 dpsnprintf(temp, sizeof(temp), "Light #%i properties:", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5738 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, FONT_DEFAULT);y += 8;
5739 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, FONT_DEFAULT);y += 8;
5740 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, FONT_DEFAULT);y += 8;
5741 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, FONT_DEFAULT);y += 8;
5742 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, FONT_DEFAULT);y += 8;
5743 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, FONT_DEFAULT);y += 8;
5744 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, FONT_DEFAULT);y += 8;
5745 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, FONT_DEFAULT);y += 8;
5746 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, FONT_DEFAULT);y += 8;
5747 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, FONT_DEFAULT);y += 8;
5748 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, FONT_DEFAULT);y += 8;
5749 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, FONT_DEFAULT);y += 8;
5750 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, FONT_DEFAULT);y += 8;
5751 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, FONT_DEFAULT);y += 8;
5754 void R_Shadow_EditLights_ToggleShadow_f(void)
5756 if (!r_editlights.integer)
5758 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5761 if (!r_shadow_selectedlight)
5763 Con_Print("No selected light.\n");
5766 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);
5769 void R_Shadow_EditLights_ToggleCorona_f(void)
5771 if (!r_editlights.integer)
5773 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5776 if (!r_shadow_selectedlight)
5778 Con_Print("No selected light.\n");
5781 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);
5784 void R_Shadow_EditLights_Remove_f(void)
5786 if (!r_editlights.integer)
5788 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5791 if (!r_shadow_selectedlight)
5793 Con_Print("No selected light.\n");
5796 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5797 r_shadow_selectedlight = NULL;
5800 void R_Shadow_EditLights_Help_f(void)
5803 "Documentation on r_editlights system:\n"
5805 "r_editlights : enable/disable editing mode\n"
5806 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5807 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5808 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5809 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5810 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5812 "r_editlights_help : this help\n"
5813 "r_editlights_clear : remove all lights\n"
5814 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5815 "r_editlights_save : save to .rtlights file\n"
5816 "r_editlights_spawn : create a light with default settings\n"
5817 "r_editlights_edit command : edit selected light - more documentation below\n"
5818 "r_editlights_remove : remove selected light\n"
5819 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5820 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5821 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5823 "origin x y z : set light location\n"
5824 "originx x: set x component of light location\n"
5825 "originy y: set y component of light location\n"
5826 "originz z: set z component of light location\n"
5827 "move x y z : adjust light location\n"
5828 "movex x: adjust x component of light location\n"
5829 "movey y: adjust y component of light location\n"
5830 "movez z: adjust z component of light location\n"
5831 "angles x y z : set light angles\n"
5832 "anglesx x: set x component of light angles\n"
5833 "anglesy y: set y component of light angles\n"
5834 "anglesz z: set z component of light angles\n"
5835 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5836 "radius radius : set radius (size) of light\n"
5837 "colorscale grey : multiply color of light (1 does nothing)\n"
5838 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5839 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5840 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5841 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5842 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5843 "shadows 1/0 : turn on/off shadows\n"
5844 "corona n : set corona intensity\n"
5845 "coronasize n : set corona size (0-1)\n"
5846 "ambient n : set ambient intensity (0-1)\n"
5847 "diffuse n : set diffuse intensity (0-1)\n"
5848 "specular n : set specular intensity (0-1)\n"
5849 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5850 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5851 "<nothing> : print light properties to console\n"
5855 void R_Shadow_EditLights_CopyInfo_f(void)
5857 if (!r_editlights.integer)
5859 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5862 if (!r_shadow_selectedlight)
5864 Con_Print("No selected light.\n");
5867 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5868 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5869 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5870 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5871 if (r_shadow_selectedlight->cubemapname)
5872 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5874 r_shadow_bufferlight.cubemapname[0] = 0;
5875 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5876 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5877 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5878 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5879 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5880 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5881 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5884 void R_Shadow_EditLights_PasteInfo_f(void)
5886 if (!r_editlights.integer)
5888 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5891 if (!r_shadow_selectedlight)
5893 Con_Print("No selected light.\n");
5896 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);
5899 void R_Shadow_EditLights_Init(void)
5901 Cvar_RegisterVariable(&r_editlights);
5902 Cvar_RegisterVariable(&r_editlights_cursordistance);
5903 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5904 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5905 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5906 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5907 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5908 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5909 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)");
5910 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5911 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5912 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5913 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)");
5914 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5915 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5916 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5917 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5918 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5919 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5920 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)");
5926 =============================================================================
5930 =============================================================================
5933 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5935 VectorClear(diffusecolor);
5936 VectorClear(diffusenormal);
5938 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5940 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
5941 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5944 VectorSet(ambientcolor, 1, 1, 1);
5951 for (i = 0;i < r_refdef.scene.numlights;i++)
5953 light = r_refdef.scene.lights[i];
5954 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5955 f = 1 - VectorLength2(v);
5956 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5957 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);