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"
142 #include "dpsoftrast.h"
146 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
149 static void R_Shadow_EditLights_Init(void);
151 typedef enum r_shadow_rendermode_e
153 R_SHADOW_RENDERMODE_NONE,
154 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
155 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
156 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
157 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
158 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
159 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
160 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
161 R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN,
162 R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN,
163 R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN,
164 R_SHADOW_RENDERMODE_LIGHT_GLSL,
165 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
166 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
167 R_SHADOW_RENDERMODE_SHADOWMAP2D
169 r_shadow_rendermode_t;
171 typedef enum r_shadow_shadowmode_e
173 R_SHADOW_SHADOWMODE_STENCIL,
174 R_SHADOW_SHADOWMODE_SHADOWMAP2D
176 r_shadow_shadowmode_t;
178 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
180 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
181 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
182 qboolean r_shadow_usingshadowmap2d;
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_fbo2d;
193 r_shadow_shadowmode_t r_shadow_shadowmode;
194 int r_shadow_shadowmapfilterquality;
195 int r_shadow_shadowmapdepthbits;
196 int r_shadow_shadowmapmaxsize;
197 qboolean r_shadow_shadowmapvsdct;
198 qboolean r_shadow_shadowmapsampler;
199 qboolean r_shadow_shadowmapshadowsampler;
200 int r_shadow_shadowmappcf;
201 int r_shadow_shadowmapborder;
202 matrix4x4_t r_shadow_shadowmapmatrix;
203 int r_shadow_lightscissor[4];
204 qboolean r_shadow_usingdeferredprepass;
205 qboolean r_shadow_shadowmapdepthtexture;
206 int maxshadowtriangles;
209 int maxshadowvertices;
210 float *shadowvertex3f;
220 unsigned char *shadowsides;
221 int *shadowsideslist;
228 int r_shadow_buffer_numleafpvsbytes;
229 unsigned char *r_shadow_buffer_visitingleafpvs;
230 unsigned char *r_shadow_buffer_leafpvs;
231 int *r_shadow_buffer_leaflist;
233 int r_shadow_buffer_numsurfacepvsbytes;
234 unsigned char *r_shadow_buffer_surfacepvs;
235 int *r_shadow_buffer_surfacelist;
236 unsigned char *r_shadow_buffer_surfacesides;
238 int r_shadow_buffer_numshadowtrispvsbytes;
239 unsigned char *r_shadow_buffer_shadowtrispvs;
240 int r_shadow_buffer_numlighttrispvsbytes;
241 unsigned char *r_shadow_buffer_lighttrispvs;
243 rtexturepool_t *r_shadow_texturepool;
244 rtexture_t *r_shadow_attenuationgradienttexture;
245 rtexture_t *r_shadow_attenuation2dtexture;
246 rtexture_t *r_shadow_attenuation3dtexture;
247 skinframe_t *r_shadow_lightcorona;
248 rtexture_t *r_shadow_shadowmap2ddepthbuffer;
249 rtexture_t *r_shadow_shadowmap2ddepthtexture;
250 rtexture_t *r_shadow_shadowmapvsdcttexture;
251 int r_shadow_shadowmapsize; // changes for each light based on distance
252 int r_shadow_shadowmaplod; // changes for each light based on distance
254 GLuint r_shadow_prepassgeometryfbo;
255 GLuint r_shadow_prepasslightingdiffusespecularfbo;
256 GLuint r_shadow_prepasslightingdiffusefbo;
257 int r_shadow_prepass_width;
258 int r_shadow_prepass_height;
259 rtexture_t *r_shadow_prepassgeometrydepthbuffer;
260 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
261 rtexture_t *r_shadow_prepasslightingdiffusetexture;
262 rtexture_t *r_shadow_prepasslightingspeculartexture;
264 // keep track of the provided framebuffer info
265 static int r_shadow_fb_fbo;
266 static rtexture_t *r_shadow_fb_depthtexture;
267 static rtexture_t *r_shadow_fb_colortexture;
269 // lights are reloaded when this changes
270 char r_shadow_mapname[MAX_QPATH];
272 // buffer for doing corona fading
273 unsigned int r_shadow_occlusion_buf = 0;
275 // used only for light filters (cubemaps)
276 rtexturepool_t *r_shadow_filters_texturepool;
278 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"};
279 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"};
280 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
281 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"};
282 cvar_t r_shadow_usebihculling = {0, "r_shadow_usebihculling", "1", "use BIH (Bounding Interval Hierarchy) for culling lit surfaces instead of BSP (Binary Space Partitioning)"};
283 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
284 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)"};
285 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"};
286 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
287 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
288 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
289 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
290 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
291 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
292 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
293 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
294 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
295 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)"};
296 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
297 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
298 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
299 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
300 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)"};
301 cvar_t r_shadow_realtime_world_importlightentitiesfrommap = {0, "r_shadow_realtime_world_importlightentitiesfrommap", "1", "load lights from .ent file or map entities at startup if no .rtlights or .lights file is present (if set to 2, always use the .ent or map entities)"};
302 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"};
303 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
304 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
305 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"};
306 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)"};
307 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
308 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)"};
309 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "1", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"};
310 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)"};
311 cvar_t r_shadow_shadowmapping_useshadowsampler = {CVAR_SAVE, "r_shadow_shadowmapping_useshadowsampler", "1", "whether to use sampler2DShadow if available"};
312 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
313 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
314 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
315 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
316 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"};
317 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
318 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
319 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
320 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
321 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
322 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
323 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
324 cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
325 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
326 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)"};
327 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)"};
328 cvar_t r_shadow_bouncegrid = {CVAR_SAVE, "r_shadow_bouncegrid", "0", "perform particle tracing for indirect lighting (Global Illumination / radiosity) using a 3D texture covering the scene, only active on levels with realtime lights active (r_shadow_realtime_world is usually required for these)"};
329 cvar_t r_shadow_bouncegrid_bounceanglediffuse = {CVAR_SAVE, "r_shadow_bouncegrid_bounceanglediffuse", "0", "use random bounce direction rather than true reflection, makes some corner areas dark"};
330 cvar_t r_shadow_bouncegrid_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_directionalshading", "0", "use diffuse shading rather than ambient, 3D texture becomes 8x as many pixels to hold the additional data"};
331 cvar_t r_shadow_bouncegrid_dlightparticlemultiplier = {CVAR_SAVE, "r_shadow_bouncegrid_dlightparticlemultiplier", "0", "if set to a high value like 16 this can make dlights look great, but 0 is recommended for performance reasons"};
332 cvar_t r_shadow_bouncegrid_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
333 cvar_t r_shadow_bouncegrid_includedirectlighting = {CVAR_SAVE, "r_shadow_bouncegrid_includedirectlighting", "0", "allows direct lighting to be recorded, not just indirect (gives an effect somewhat like r_shadow_realtime_world_lightmaps)"};
334 cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
335 cvar_t r_shadow_bouncegrid_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_lightradiusscale", "4", "particles stop at this fraction of light radius (can be more than 1)"};
336 cvar_t r_shadow_bouncegrid_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_maxbounce", "2", "maximum number of bounces for a particle (minimum is 0)"};
337 cvar_t r_shadow_bouncegrid_particlebounceintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particlebounceintensity", "1", "amount of energy carried over after each bounce, this is a multiplier of texture color and the result is clamped to 1 or less, to prevent adding energy on each bounce"};
338 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "1", "brightness of particles contributing to bouncegrid texture"};
339 cvar_t r_shadow_bouncegrid_maxphotons = {CVAR_SAVE, "r_shadow_bouncegrid_maxphotons", "25000", "upper bound on photons to shoot per update, divided proportionately between lights - normally the number of photons is calculated by intensityperphoton"};
340 cvar_t r_shadow_bouncegrid_intensityperphoton = {CVAR_SAVE, "r_shadow_bouncegrid_intensityperphoton", "10000", "amount of light that one photon should represent"};
341 cvar_t r_shadow_bouncegrid_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_spacing", "64", "unit size of bouncegrid pixel"};
342 cvar_t r_shadow_bouncegrid_stablerandom = {CVAR_SAVE, "r_shadow_bouncegrid_stablerandom", "1", "make particle distribution consistent from frame to frame"};
343 cvar_t r_shadow_bouncegrid_static = {CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
344 cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
345 cvar_t r_shadow_bouncegrid_static_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_static_lightradiusscale", "10", "particles stop at this fraction of light radius (can be more than 1) when in static mode"};
346 cvar_t r_shadow_bouncegrid_static_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_static_maxbounce", "5", "maximum number of bounces for a particle (minimum is 0) in static mode"};
347 cvar_t r_shadow_bouncegrid_static_maxphotons = {CVAR_SAVE, "r_shadow_bouncegrid_static_maxphotons", "250000", "upper bound on photons in static mode"};
348 cvar_t r_shadow_bouncegrid_static_intensityperphoton = {CVAR_SAVE, "r_shadow_bouncegrid_static_intensityperphoton", "1000", "amount of light that one photon should represent in static mode"};
349 cvar_t r_shadow_bouncegrid_updateinterval = {CVAR_SAVE, "r_shadow_bouncegrid_updateinterval", "0", "update bouncegrid texture once per this many seconds, useful values are 0, 0.05, or 1000000"};
350 cvar_t r_shadow_bouncegrid_x = {CVAR_SAVE, "r_shadow_bouncegrid_x", "64", "maximum texture size of bouncegrid on X axis"};
351 cvar_t r_shadow_bouncegrid_y = {CVAR_SAVE, "r_shadow_bouncegrid_y", "64", "maximum texture size of bouncegrid on Y axis"};
352 cvar_t r_shadow_bouncegrid_z = {CVAR_SAVE, "r_shadow_bouncegrid_z", "32", "maximum texture size of bouncegrid on Z axis"};
353 cvar_t r_shadow_bouncegrid_culllightpaths = {CVAR_SAVE, "r_shadow_bouncegrid_culllightpaths", "1", "skip accumulating light in the bouncegrid texture where the light paths are out of view (dynamic mode only)"};
354 cvar_t r_shadow_bouncegrid_sortlightpaths = {CVAR_SAVE, "r_shadow_bouncegrid_sortlightpaths", "1", "sort light paths before accumulating them into the bouncegrid texture, this reduces cpu cache misses"};
355 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
356 cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksum the proportion of hidden pixels controls corona intensity"};
357 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "0", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility) - bad performance (synchronous rendering) - worse on multi-gpu!"};
358 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
359 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
360 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
361 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
362 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
363 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
364 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
365 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
366 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
367 cvar_t r_editlights_drawproperties = {0, "r_editlights_drawproperties", "1", "draw properties of currently selected light"};
368 cvar_t r_editlights_current_origin = {0, "r_editlights_current_origin", "0 0 0", "origin of selected light"};
369 cvar_t r_editlights_current_angles = {0, "r_editlights_current_angles", "0 0 0", "angles of selected light"};
370 cvar_t r_editlights_current_color = {0, "r_editlights_current_color", "1 1 1", "color of selected light"};
371 cvar_t r_editlights_current_radius = {0, "r_editlights_current_radius", "0", "radius of selected light"};
372 cvar_t r_editlights_current_corona = {0, "r_editlights_current_corona", "0", "corona intensity of selected light"};
373 cvar_t r_editlights_current_coronasize = {0, "r_editlights_current_coronasize", "0", "corona size of selected light"};
374 cvar_t r_editlights_current_style = {0, "r_editlights_current_style", "0", "style of selected light"};
375 cvar_t r_editlights_current_shadows = {0, "r_editlights_current_shadows", "0", "shadows flag of selected light"};
376 cvar_t r_editlights_current_cubemap = {0, "r_editlights_current_cubemap", "0", "cubemap of selected light"};
377 cvar_t r_editlights_current_ambient = {0, "r_editlights_current_ambient", "0", "ambient intensity of selected light"};
378 cvar_t r_editlights_current_diffuse = {0, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"};
379 cvar_t r_editlights_current_specular = {0, "r_editlights_current_specular", "1", "specular intensity of selected light"};
380 cvar_t r_editlights_current_normalmode = {0, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"};
381 cvar_t r_editlights_current_realtimemode = {0, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"};
383 r_shadow_bouncegrid_state_t r_shadow_bouncegrid_state;
385 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
386 #define ATTENTABLESIZE 256
387 // 1D gradient, 2D circle and 3D sphere attenuation textures
388 #define ATTEN1DSIZE 32
389 #define ATTEN2DSIZE 64
390 #define ATTEN3DSIZE 32
392 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
393 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
394 static float r_shadow_attentable[ATTENTABLESIZE+1];
396 rtlight_t *r_shadow_compilingrtlight;
397 static memexpandablearray_t r_shadow_worldlightsarray;
398 dlight_t *r_shadow_selectedlight;
399 dlight_t r_shadow_bufferlight;
400 vec3_t r_editlights_cursorlocation;
401 qboolean r_editlights_lockcursor;
403 extern int con_vislines;
405 void R_Shadow_UncompileWorldLights(void);
406 void R_Shadow_ClearWorldLights(void);
407 void R_Shadow_SaveWorldLights(void);
408 void R_Shadow_LoadWorldLights(void);
409 void R_Shadow_LoadLightsFile(void);
410 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
411 void R_Shadow_EditLights_Reload_f(void);
412 void R_Shadow_ValidateCvars(void);
413 static void R_Shadow_MakeTextures(void);
415 #define EDLIGHTSPRSIZE 8
416 skinframe_t *r_editlights_sprcursor;
417 skinframe_t *r_editlights_sprlight;
418 skinframe_t *r_editlights_sprnoshadowlight;
419 skinframe_t *r_editlights_sprcubemaplight;
420 skinframe_t *r_editlights_sprcubemapnoshadowlight;
421 skinframe_t *r_editlights_sprselection;
423 static void R_Shadow_SetShadowMode(void)
425 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
426 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
427 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
428 r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
429 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
430 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
431 r_shadow_shadowmaplod = -1;
432 r_shadow_shadowmapsize = 0;
433 r_shadow_shadowmapsampler = false;
434 r_shadow_shadowmappcf = 0;
435 r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
436 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
437 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
439 switch(vid.renderpath)
441 case RENDERPATH_GL20:
442 if(r_shadow_shadowmapfilterquality < 0)
444 if (!r_fb.usedepthtextures)
445 r_shadow_shadowmappcf = 1;
446 else if((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && vid.support.arb_shadow && r_shadow_shadowmapshadowsampler)
448 r_shadow_shadowmapsampler = true;
449 r_shadow_shadowmappcf = 1;
451 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
452 r_shadow_shadowmappcf = 1;
453 else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa"))
454 r_shadow_shadowmappcf = 1;
456 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
460 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
461 switch (r_shadow_shadowmapfilterquality)
466 r_shadow_shadowmappcf = 1;
469 r_shadow_shadowmappcf = 1;
472 r_shadow_shadowmappcf = 2;
476 if (!r_fb.usedepthtextures)
477 r_shadow_shadowmapsampler = false;
478 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
480 case RENDERPATH_D3D9:
481 case RENDERPATH_D3D10:
482 case RENDERPATH_D3D11:
483 case RENDERPATH_SOFT:
484 r_shadow_shadowmapsampler = false;
485 r_shadow_shadowmappcf = 1;
486 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
488 case RENDERPATH_GL11:
489 case RENDERPATH_GL13:
490 case RENDERPATH_GLES1:
491 case RENDERPATH_GLES2:
496 if(R_CompileShader_CheckStaticParms())
500 qboolean R_Shadow_ShadowMappingEnabled(void)
502 switch (r_shadow_shadowmode)
504 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
511 static void R_Shadow_FreeShadowMaps(void)
513 R_Shadow_SetShadowMode();
515 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
519 if (r_shadow_shadowmap2ddepthtexture)
520 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
521 r_shadow_shadowmap2ddepthtexture = NULL;
523 if (r_shadow_shadowmap2ddepthbuffer)
524 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
525 r_shadow_shadowmap2ddepthbuffer = NULL;
527 if (r_shadow_shadowmapvsdcttexture)
528 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
529 r_shadow_shadowmapvsdcttexture = NULL;
532 static void r_shadow_start(void)
534 // allocate vertex processing arrays
535 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
536 r_shadow_bouncegrid_state.maxsplatpaths = 16384;
537 r_shadow_attenuationgradienttexture = NULL;
538 r_shadow_attenuation2dtexture = NULL;
539 r_shadow_attenuation3dtexture = NULL;
540 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
541 r_shadow_shadowmap2ddepthtexture = NULL;
542 r_shadow_shadowmap2ddepthbuffer = NULL;
543 r_shadow_shadowmapvsdcttexture = NULL;
544 r_shadow_shadowmapmaxsize = 0;
545 r_shadow_shadowmapsize = 0;
546 r_shadow_shadowmaplod = 0;
547 r_shadow_shadowmapfilterquality = -1;
548 r_shadow_shadowmapdepthbits = 0;
549 r_shadow_shadowmapvsdct = false;
550 r_shadow_shadowmapsampler = false;
551 r_shadow_shadowmappcf = 0;
554 R_Shadow_FreeShadowMaps();
556 r_shadow_texturepool = NULL;
557 r_shadow_filters_texturepool = NULL;
558 R_Shadow_ValidateCvars();
559 R_Shadow_MakeTextures();
560 maxshadowtriangles = 0;
561 shadowelements = NULL;
562 maxshadowvertices = 0;
563 shadowvertex3f = NULL;
571 shadowmarklist = NULL;
576 shadowsideslist = NULL;
577 r_shadow_buffer_numleafpvsbytes = 0;
578 r_shadow_buffer_visitingleafpvs = NULL;
579 r_shadow_buffer_leafpvs = NULL;
580 r_shadow_buffer_leaflist = NULL;
581 r_shadow_buffer_numsurfacepvsbytes = 0;
582 r_shadow_buffer_surfacepvs = NULL;
583 r_shadow_buffer_surfacelist = NULL;
584 r_shadow_buffer_surfacesides = NULL;
585 r_shadow_buffer_numshadowtrispvsbytes = 0;
586 r_shadow_buffer_shadowtrispvs = NULL;
587 r_shadow_buffer_numlighttrispvsbytes = 0;
588 r_shadow_buffer_lighttrispvs = NULL;
590 r_shadow_usingdeferredprepass = false;
591 r_shadow_prepass_width = r_shadow_prepass_height = 0;
593 // determine renderpath specific capabilities, we don't need to figure
594 // these out per frame...
595 switch(vid.renderpath)
597 case RENDERPATH_GL20:
598 r_shadow_bouncegrid_state.allowdirectionalshading = true;
599 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
601 case RENDERPATH_GLES2:
602 // for performance reasons, do not use directional shading on GLES devices
603 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
605 // these renderpaths do not currently have the code to display the bouncegrid, so disable it on them...
606 case RENDERPATH_GL11:
607 case RENDERPATH_GL13:
608 case RENDERPATH_GLES1:
609 case RENDERPATH_SOFT:
610 case RENDERPATH_D3D9:
611 case RENDERPATH_D3D10:
612 case RENDERPATH_D3D11:
617 static void R_Shadow_FreeDeferred(void);
618 static void r_shadow_shutdown(void)
621 R_Shadow_UncompileWorldLights();
623 R_Shadow_FreeShadowMaps();
625 r_shadow_usingdeferredprepass = false;
626 if (r_shadow_prepass_width)
627 R_Shadow_FreeDeferred();
628 r_shadow_prepass_width = r_shadow_prepass_height = 0;
631 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
632 r_shadow_attenuationgradienttexture = NULL;
633 r_shadow_attenuation2dtexture = NULL;
634 r_shadow_attenuation3dtexture = NULL;
635 R_FreeTexturePool(&r_shadow_texturepool);
636 R_FreeTexturePool(&r_shadow_filters_texturepool);
637 maxshadowtriangles = 0;
639 Mem_Free(shadowelements);
640 shadowelements = NULL;
642 Mem_Free(shadowvertex3f);
643 shadowvertex3f = NULL;
646 Mem_Free(vertexupdate);
649 Mem_Free(vertexremap);
655 Mem_Free(shadowmark);
658 Mem_Free(shadowmarklist);
659 shadowmarklist = NULL;
664 Mem_Free(shadowsides);
667 Mem_Free(shadowsideslist);
668 shadowsideslist = NULL;
669 r_shadow_buffer_numleafpvsbytes = 0;
670 if (r_shadow_buffer_visitingleafpvs)
671 Mem_Free(r_shadow_buffer_visitingleafpvs);
672 r_shadow_buffer_visitingleafpvs = NULL;
673 if (r_shadow_buffer_leafpvs)
674 Mem_Free(r_shadow_buffer_leafpvs);
675 r_shadow_buffer_leafpvs = NULL;
676 if (r_shadow_buffer_leaflist)
677 Mem_Free(r_shadow_buffer_leaflist);
678 r_shadow_buffer_leaflist = NULL;
679 r_shadow_buffer_numsurfacepvsbytes = 0;
680 if (r_shadow_buffer_surfacepvs)
681 Mem_Free(r_shadow_buffer_surfacepvs);
682 r_shadow_buffer_surfacepvs = NULL;
683 if (r_shadow_buffer_surfacelist)
684 Mem_Free(r_shadow_buffer_surfacelist);
685 r_shadow_buffer_surfacelist = NULL;
686 if (r_shadow_buffer_surfacesides)
687 Mem_Free(r_shadow_buffer_surfacesides);
688 r_shadow_buffer_surfacesides = NULL;
689 r_shadow_buffer_numshadowtrispvsbytes = 0;
690 if (r_shadow_buffer_shadowtrispvs)
691 Mem_Free(r_shadow_buffer_shadowtrispvs);
692 r_shadow_buffer_numlighttrispvsbytes = 0;
693 if (r_shadow_buffer_lighttrispvs)
694 Mem_Free(r_shadow_buffer_lighttrispvs);
697 static void r_shadow_newmap(void)
699 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
700 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
701 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
702 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
703 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
704 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
705 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
706 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
707 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
708 R_Shadow_EditLights_Reload_f();
711 void R_Shadow_Init(void)
713 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
714 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
715 Cvar_RegisterVariable(&r_shadow_usebihculling);
716 Cvar_RegisterVariable(&r_shadow_usenormalmap);
717 Cvar_RegisterVariable(&r_shadow_debuglight);
718 Cvar_RegisterVariable(&r_shadow_deferred);
719 Cvar_RegisterVariable(&r_shadow_gloss);
720 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
721 Cvar_RegisterVariable(&r_shadow_glossintensity);
722 Cvar_RegisterVariable(&r_shadow_glossexponent);
723 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
724 Cvar_RegisterVariable(&r_shadow_glossexact);
725 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
726 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
727 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
728 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
729 Cvar_RegisterVariable(&r_shadow_projectdistance);
730 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
731 Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
732 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
733 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
734 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
735 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
736 Cvar_RegisterVariable(&r_shadow_realtime_world);
737 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
738 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
739 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
740 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
741 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
742 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
743 Cvar_RegisterVariable(&r_shadow_scissor);
744 Cvar_RegisterVariable(&r_shadow_shadowmapping);
745 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
746 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
747 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
748 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
749 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
750 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
751 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
752 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
753 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
754 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
755 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
756 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
757 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
758 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
759 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
760 Cvar_RegisterVariable(&r_shadow_polygonfactor);
761 Cvar_RegisterVariable(&r_shadow_polygonoffset);
762 Cvar_RegisterVariable(&r_shadow_texture3d);
763 Cvar_RegisterVariable(&r_shadow_bouncegrid);
764 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
765 Cvar_RegisterVariable(&r_shadow_bouncegrid_directionalshading);
766 Cvar_RegisterVariable(&r_shadow_bouncegrid_dlightparticlemultiplier);
767 Cvar_RegisterVariable(&r_shadow_bouncegrid_hitmodels);
768 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
769 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
770 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightradiusscale);
771 Cvar_RegisterVariable(&r_shadow_bouncegrid_maxbounce);
772 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
773 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
774 Cvar_RegisterVariable(&r_shadow_bouncegrid_maxphotons);
775 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensityperphoton);
776 Cvar_RegisterVariable(&r_shadow_bouncegrid_spacing);
777 Cvar_RegisterVariable(&r_shadow_bouncegrid_stablerandom);
778 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
779 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
780 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
781 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
782 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxphotons);
783 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_intensityperphoton);
784 Cvar_RegisterVariable(&r_shadow_bouncegrid_updateinterval);
785 Cvar_RegisterVariable(&r_shadow_bouncegrid_x);
786 Cvar_RegisterVariable(&r_shadow_bouncegrid_y);
787 Cvar_RegisterVariable(&r_shadow_bouncegrid_z);
788 Cvar_RegisterVariable(&r_shadow_bouncegrid_culllightpaths);
789 Cvar_RegisterVariable(&r_shadow_bouncegrid_sortlightpaths);
790 Cvar_RegisterVariable(&r_coronas);
791 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
792 Cvar_RegisterVariable(&r_coronas_occlusionquery);
793 Cvar_RegisterVariable(&gl_flashblend);
794 Cvar_RegisterVariable(&gl_ext_separatestencil);
795 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
796 R_Shadow_EditLights_Init();
797 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
798 maxshadowtriangles = 0;
799 shadowelements = NULL;
800 maxshadowvertices = 0;
801 shadowvertex3f = NULL;
809 shadowmarklist = NULL;
814 shadowsideslist = NULL;
815 r_shadow_buffer_numleafpvsbytes = 0;
816 r_shadow_buffer_visitingleafpvs = NULL;
817 r_shadow_buffer_leafpvs = NULL;
818 r_shadow_buffer_leaflist = NULL;
819 r_shadow_buffer_numsurfacepvsbytes = 0;
820 r_shadow_buffer_surfacepvs = NULL;
821 r_shadow_buffer_surfacelist = NULL;
822 r_shadow_buffer_surfacesides = NULL;
823 r_shadow_buffer_shadowtrispvs = NULL;
824 r_shadow_buffer_lighttrispvs = NULL;
825 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
828 matrix4x4_t matrix_attenuationxyz =
831 {0.5, 0.0, 0.0, 0.5},
832 {0.0, 0.5, 0.0, 0.5},
833 {0.0, 0.0, 0.5, 0.5},
838 matrix4x4_t matrix_attenuationz =
841 {0.0, 0.0, 0.5, 0.5},
842 {0.0, 0.0, 0.0, 0.5},
843 {0.0, 0.0, 0.0, 0.5},
848 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
850 numvertices = ((numvertices + 255) & ~255) * vertscale;
851 numtriangles = ((numtriangles + 255) & ~255) * triscale;
852 // make sure shadowelements is big enough for this volume
853 if (maxshadowtriangles < numtriangles)
855 maxshadowtriangles = numtriangles;
857 Mem_Free(shadowelements);
858 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
860 // make sure shadowvertex3f is big enough for this volume
861 if (maxshadowvertices < numvertices)
863 maxshadowvertices = numvertices;
865 Mem_Free(shadowvertex3f);
866 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
870 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
872 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
873 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
874 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
875 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
876 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
878 if (r_shadow_buffer_visitingleafpvs)
879 Mem_Free(r_shadow_buffer_visitingleafpvs);
880 if (r_shadow_buffer_leafpvs)
881 Mem_Free(r_shadow_buffer_leafpvs);
882 if (r_shadow_buffer_leaflist)
883 Mem_Free(r_shadow_buffer_leaflist);
884 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
885 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
886 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
887 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
889 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
891 if (r_shadow_buffer_surfacepvs)
892 Mem_Free(r_shadow_buffer_surfacepvs);
893 if (r_shadow_buffer_surfacelist)
894 Mem_Free(r_shadow_buffer_surfacelist);
895 if (r_shadow_buffer_surfacesides)
896 Mem_Free(r_shadow_buffer_surfacesides);
897 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
898 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
899 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
900 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
902 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
904 if (r_shadow_buffer_shadowtrispvs)
905 Mem_Free(r_shadow_buffer_shadowtrispvs);
906 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
907 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
909 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
911 if (r_shadow_buffer_lighttrispvs)
912 Mem_Free(r_shadow_buffer_lighttrispvs);
913 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
914 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
918 void R_Shadow_PrepareShadowMark(int numtris)
920 // make sure shadowmark is big enough for this volume
921 if (maxshadowmark < numtris)
923 maxshadowmark = numtris;
925 Mem_Free(shadowmark);
927 Mem_Free(shadowmarklist);
928 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
929 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
933 // if shadowmarkcount wrapped we clear the array and adjust accordingly
934 if (shadowmarkcount == 0)
937 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
942 void R_Shadow_PrepareShadowSides(int numtris)
944 if (maxshadowsides < numtris)
946 maxshadowsides = numtris;
948 Mem_Free(shadowsides);
950 Mem_Free(shadowsideslist);
951 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
952 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
957 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)
960 int outtriangles = 0, outvertices = 0;
963 float ratio, direction[3], projectvector[3];
965 if (projectdirection)
966 VectorScale(projectdirection, projectdistance, projectvector);
968 VectorClear(projectvector);
970 // create the vertices
971 if (projectdirection)
973 for (i = 0;i < numshadowmarktris;i++)
975 element = inelement3i + shadowmarktris[i] * 3;
976 for (j = 0;j < 3;j++)
978 if (vertexupdate[element[j]] != vertexupdatenum)
980 vertexupdate[element[j]] = vertexupdatenum;
981 vertexremap[element[j]] = outvertices;
982 vertex = invertex3f + element[j] * 3;
983 // project one copy of the vertex according to projectvector
984 VectorCopy(vertex, outvertex3f);
985 VectorAdd(vertex, projectvector, (outvertex3f + 3));
994 for (i = 0;i < numshadowmarktris;i++)
996 element = inelement3i + shadowmarktris[i] * 3;
997 for (j = 0;j < 3;j++)
999 if (vertexupdate[element[j]] != vertexupdatenum)
1001 vertexupdate[element[j]] = vertexupdatenum;
1002 vertexremap[element[j]] = outvertices;
1003 vertex = invertex3f + element[j] * 3;
1004 // project one copy of the vertex to the sphere radius of the light
1005 // (FIXME: would projecting it to the light box be better?)
1006 VectorSubtract(vertex, projectorigin, direction);
1007 ratio = projectdistance / VectorLength(direction);
1008 VectorCopy(vertex, outvertex3f);
1009 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1017 if (r_shadow_frontsidecasting.integer)
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[0]];
1030 outelement3i[1] = vertexremap[element[1]];
1031 outelement3i[2] = vertexremap[element[2]];
1032 outelement3i[3] = vertexremap[element[2]] + 1;
1033 outelement3i[4] = vertexremap[element[1]] + 1;
1034 outelement3i[5] = vertexremap[element[0]] + 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[1];
1044 outelement3i[1] = remappedelement[0];
1045 outelement3i[2] = remappedelement[0] + 1;
1046 outelement3i[3] = remappedelement[1];
1047 outelement3i[4] = remappedelement[0] + 1;
1048 outelement3i[5] = remappedelement[1] + 1;
1053 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1055 remappedelement[1] = vertexremap[element[1]];
1056 remappedelement[2] = vertexremap[element[2]];
1057 outelement3i[0] = remappedelement[2];
1058 outelement3i[1] = remappedelement[1];
1059 outelement3i[2] = remappedelement[1] + 1;
1060 outelement3i[3] = remappedelement[2];
1061 outelement3i[4] = remappedelement[1] + 1;
1062 outelement3i[5] = remappedelement[2] + 1;
1067 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1069 remappedelement[0] = vertexremap[element[0]];
1070 remappedelement[2] = vertexremap[element[2]];
1071 outelement3i[0] = remappedelement[0];
1072 outelement3i[1] = remappedelement[2];
1073 outelement3i[2] = remappedelement[2] + 1;
1074 outelement3i[3] = remappedelement[0];
1075 outelement3i[4] = remappedelement[2] + 1;
1076 outelement3i[5] = remappedelement[0] + 1;
1085 for (i = 0;i < numshadowmarktris;i++)
1087 int remappedelement[3];
1089 const int *neighbortriangle;
1091 markindex = shadowmarktris[i] * 3;
1092 element = inelement3i + markindex;
1093 neighbortriangle = inneighbor3i + markindex;
1094 // output the front and back triangles
1095 outelement3i[0] = vertexremap[element[2]];
1096 outelement3i[1] = vertexremap[element[1]];
1097 outelement3i[2] = vertexremap[element[0]];
1098 outelement3i[3] = vertexremap[element[0]] + 1;
1099 outelement3i[4] = vertexremap[element[1]] + 1;
1100 outelement3i[5] = vertexremap[element[2]] + 1;
1104 // output the sides (facing outward from this triangle)
1105 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1107 remappedelement[0] = vertexremap[element[0]];
1108 remappedelement[1] = vertexremap[element[1]];
1109 outelement3i[0] = remappedelement[0];
1110 outelement3i[1] = remappedelement[1];
1111 outelement3i[2] = remappedelement[1] + 1;
1112 outelement3i[3] = remappedelement[0];
1113 outelement3i[4] = remappedelement[1] + 1;
1114 outelement3i[5] = remappedelement[0] + 1;
1119 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1121 remappedelement[1] = vertexremap[element[1]];
1122 remappedelement[2] = vertexremap[element[2]];
1123 outelement3i[0] = remappedelement[1];
1124 outelement3i[1] = remappedelement[2];
1125 outelement3i[2] = remappedelement[2] + 1;
1126 outelement3i[3] = remappedelement[1];
1127 outelement3i[4] = remappedelement[2] + 1;
1128 outelement3i[5] = remappedelement[1] + 1;
1133 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1135 remappedelement[0] = vertexremap[element[0]];
1136 remappedelement[2] = vertexremap[element[2]];
1137 outelement3i[0] = remappedelement[2];
1138 outelement3i[1] = remappedelement[0];
1139 outelement3i[2] = remappedelement[0] + 1;
1140 outelement3i[3] = remappedelement[2];
1141 outelement3i[4] = remappedelement[0] + 1;
1142 outelement3i[5] = remappedelement[2] + 1;
1150 *outnumvertices = outvertices;
1151 return outtriangles;
1154 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)
1157 int outtriangles = 0, outvertices = 0;
1159 const float *vertex;
1160 float ratio, direction[3], projectvector[3];
1163 if (projectdirection)
1164 VectorScale(projectdirection, projectdistance, projectvector);
1166 VectorClear(projectvector);
1168 for (i = 0;i < numshadowmarktris;i++)
1170 int remappedelement[3];
1172 const int *neighbortriangle;
1174 markindex = shadowmarktris[i] * 3;
1175 neighbortriangle = inneighbor3i + markindex;
1176 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1177 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1178 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1179 if (side[0] + side[1] + side[2] == 0)
1183 element = inelement3i + markindex;
1185 // create the vertices
1186 for (j = 0;j < 3;j++)
1188 if (side[j] + side[j+1] == 0)
1191 if (vertexupdate[k] != vertexupdatenum)
1193 vertexupdate[k] = vertexupdatenum;
1194 vertexremap[k] = outvertices;
1195 vertex = invertex3f + k * 3;
1196 VectorCopy(vertex, outvertex3f);
1197 if (projectdirection)
1199 // project one copy of the vertex according to projectvector
1200 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1204 // project one copy of the vertex to the sphere radius of the light
1205 // (FIXME: would projecting it to the light box be better?)
1206 VectorSubtract(vertex, projectorigin, direction);
1207 ratio = projectdistance / VectorLength(direction);
1208 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1215 // output the sides (facing outward from this triangle)
1218 remappedelement[0] = vertexremap[element[0]];
1219 remappedelement[1] = vertexremap[element[1]];
1220 outelement3i[0] = remappedelement[1];
1221 outelement3i[1] = remappedelement[0];
1222 outelement3i[2] = remappedelement[0] + 1;
1223 outelement3i[3] = remappedelement[1];
1224 outelement3i[4] = remappedelement[0] + 1;
1225 outelement3i[5] = remappedelement[1] + 1;
1232 remappedelement[1] = vertexremap[element[1]];
1233 remappedelement[2] = vertexremap[element[2]];
1234 outelement3i[0] = remappedelement[2];
1235 outelement3i[1] = remappedelement[1];
1236 outelement3i[2] = remappedelement[1] + 1;
1237 outelement3i[3] = remappedelement[2];
1238 outelement3i[4] = remappedelement[1] + 1;
1239 outelement3i[5] = remappedelement[2] + 1;
1246 remappedelement[0] = vertexremap[element[0]];
1247 remappedelement[2] = vertexremap[element[2]];
1248 outelement3i[0] = remappedelement[0];
1249 outelement3i[1] = remappedelement[2];
1250 outelement3i[2] = remappedelement[2] + 1;
1251 outelement3i[3] = remappedelement[0];
1252 outelement3i[4] = remappedelement[2] + 1;
1253 outelement3i[5] = remappedelement[0] + 1;
1260 *outnumvertices = outvertices;
1261 return outtriangles;
1264 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)
1270 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1272 tend = firsttriangle + numtris;
1273 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1275 // surface box entirely inside light box, no box cull
1276 if (projectdirection)
1278 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1280 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1281 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1282 shadowmarklist[numshadowmark++] = t;
1287 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1288 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1289 shadowmarklist[numshadowmark++] = t;
1294 // surface box not entirely inside light box, cull each triangle
1295 if (projectdirection)
1297 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1299 v[0] = invertex3f + e[0] * 3;
1300 v[1] = invertex3f + e[1] * 3;
1301 v[2] = invertex3f + e[2] * 3;
1302 TriangleNormal(v[0], v[1], v[2], normal);
1303 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1304 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1305 shadowmarklist[numshadowmark++] = t;
1310 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1312 v[0] = invertex3f + e[0] * 3;
1313 v[1] = invertex3f + e[1] * 3;
1314 v[2] = invertex3f + e[2] * 3;
1315 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1316 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1317 shadowmarklist[numshadowmark++] = t;
1323 static qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1328 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1330 // check if the shadow volume intersects the near plane
1332 // a ray between the eye and light origin may intersect the caster,
1333 // indicating that the shadow may touch the eye location, however we must
1334 // test the near plane (a polygon), not merely the eye location, so it is
1335 // easiest to enlarge the caster bounding shape slightly for this.
1341 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)
1343 int i, tris, outverts;
1344 if (projectdistance < 0.1)
1346 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1349 if (!numverts || !nummarktris)
1351 // make sure shadowelements is big enough for this volume
1352 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1353 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1355 if (maxvertexupdate < numverts)
1357 maxvertexupdate = numverts;
1359 Mem_Free(vertexupdate);
1361 Mem_Free(vertexremap);
1362 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1363 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1364 vertexupdatenum = 0;
1367 if (vertexupdatenum == 0)
1369 vertexupdatenum = 1;
1370 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1371 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1374 for (i = 0;i < nummarktris;i++)
1375 shadowmark[marktris[i]] = shadowmarkcount;
1377 if (r_shadow_compilingrtlight)
1379 // if we're compiling an rtlight, capture the mesh
1380 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1381 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1382 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1383 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1385 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1387 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1388 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1389 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1393 // decide which type of shadow to generate and set stencil mode
1394 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1395 // generate the sides or a solid volume, depending on type
1396 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1397 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1399 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1400 r_refdef.stats[r_stat_lights_dynamicshadowtriangles] += tris;
1401 r_refdef.stats[r_stat_lights_shadowtriangles] += tris;
1402 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1404 // increment stencil if frontface is infront of depthbuffer
1405 GL_CullFace(r_refdef.view.cullface_front);
1406 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1407 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1408 // decrement stencil if backface is infront of depthbuffer
1409 GL_CullFace(r_refdef.view.cullface_back);
1410 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1412 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1414 // decrement stencil if backface is behind depthbuffer
1415 GL_CullFace(r_refdef.view.cullface_front);
1416 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1417 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1418 // increment stencil if frontface is behind depthbuffer
1419 GL_CullFace(r_refdef.view.cullface_back);
1420 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1422 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1423 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1427 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1429 // p1, p2, p3 are in the cubemap's local coordinate system
1430 // bias = border/(size - border)
1433 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1434 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1435 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1436 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1438 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1439 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1440 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1441 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1443 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1444 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1445 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1447 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1448 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1449 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1450 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1452 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1453 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1454 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1455 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1457 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1458 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1459 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1461 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1462 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1463 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1464 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1466 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1467 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1468 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1469 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1471 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1472 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1473 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1478 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1480 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1481 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1484 VectorSubtract(maxs, mins, radius);
1485 VectorScale(radius, 0.5f, radius);
1486 VectorAdd(mins, radius, center);
1487 Matrix4x4_Transform(worldtolight, center, lightcenter);
1488 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1489 VectorSubtract(lightcenter, lightradius, pmin);
1490 VectorAdd(lightcenter, lightradius, pmax);
1492 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1493 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1494 if(ap1 > bias*an1 && ap2 > bias*an2)
1496 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1497 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1498 if(an1 > bias*ap1 && an2 > bias*ap2)
1500 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1501 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1503 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1504 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1505 if(ap1 > bias*an1 && ap2 > bias*an2)
1507 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1508 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1509 if(an1 > bias*ap1 && an2 > bias*ap2)
1511 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1512 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1514 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1515 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1516 if(ap1 > bias*an1 && ap2 > bias*an2)
1518 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1519 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1520 if(an1 > bias*ap1 && an2 > bias*ap2)
1522 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1523 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1528 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1530 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1532 // p is in the cubemap's local coordinate system
1533 // bias = border/(size - border)
1534 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1535 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1536 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1538 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1539 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1540 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1541 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1542 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1543 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1547 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1551 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1552 float scale = (size - 2*border)/size, len;
1553 float bias = border / (float)(size - border), dp, dn, ap, an;
1554 // check if cone enclosing side would cross frustum plane
1555 scale = 2 / (scale*scale + 2);
1556 Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
1557 for (i = 0;i < 5;i++)
1559 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
1561 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1562 len = scale*VectorLength2(n);
1563 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1564 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1565 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1567 if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1569 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1570 len = scale*VectorLength2(n);
1571 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1572 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1573 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1575 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1576 // check if frustum corners/origin cross plane sides
1578 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1579 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1580 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1581 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1582 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1583 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1584 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1585 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1586 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1587 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1588 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1589 for (i = 0;i < 4;i++)
1591 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1592 VectorSubtract(n, p, n);
1593 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1594 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1595 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1596 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1597 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1598 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1599 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1600 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1601 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1604 // finite version, assumes corners are a finite distance from origin dependent on far plane
1605 for (i = 0;i < 5;i++)
1607 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1608 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1609 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1610 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1611 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1612 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1613 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1614 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1615 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1616 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1619 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1622 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)
1630 int mask, surfacemask = 0;
1631 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1633 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1634 tend = firsttriangle + numtris;
1635 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1637 // surface box entirely inside light box, no box cull
1638 if (projectdirection)
1640 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1642 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1643 TriangleNormal(v[0], v[1], v[2], normal);
1644 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1646 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1647 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1648 surfacemask |= mask;
1651 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;
1652 shadowsides[numshadowsides] = mask;
1653 shadowsideslist[numshadowsides++] = t;
1660 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1662 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1663 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1665 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1666 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1667 surfacemask |= mask;
1670 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;
1671 shadowsides[numshadowsides] = mask;
1672 shadowsideslist[numshadowsides++] = t;
1680 // surface box not entirely inside light box, cull each triangle
1681 if (projectdirection)
1683 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1685 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1686 TriangleNormal(v[0], v[1], v[2], normal);
1687 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1688 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1690 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1691 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1692 surfacemask |= mask;
1695 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;
1696 shadowsides[numshadowsides] = mask;
1697 shadowsideslist[numshadowsides++] = t;
1704 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1706 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1707 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1708 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1710 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1711 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1712 surfacemask |= mask;
1715 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;
1716 shadowsides[numshadowsides] = mask;
1717 shadowsideslist[numshadowsides++] = t;
1726 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)
1728 int i, j, outtriangles = 0;
1729 int *outelement3i[6];
1730 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1732 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1733 // make sure shadowelements is big enough for this mesh
1734 if (maxshadowtriangles < outtriangles)
1735 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1737 // compute the offset and size of the separate index lists for each cubemap side
1739 for (i = 0;i < 6;i++)
1741 outelement3i[i] = shadowelements + outtriangles * 3;
1742 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1743 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1744 outtriangles += sidetotals[i];
1747 // gather up the (sparse) triangles into separate index lists for each cubemap side
1748 for (i = 0;i < numsidetris;i++)
1750 const int *element = elements + sidetris[i] * 3;
1751 for (j = 0;j < 6;j++)
1753 if (sides[i] & (1 << j))
1755 outelement3i[j][0] = element[0];
1756 outelement3i[j][1] = element[1];
1757 outelement3i[j][2] = element[2];
1758 outelement3i[j] += 3;
1763 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1766 static void R_Shadow_MakeTextures_MakeCorona(void)
1770 unsigned char pixels[32][32][4];
1771 for (y = 0;y < 32;y++)
1773 dy = (y - 15.5f) * (1.0f / 16.0f);
1774 for (x = 0;x < 32;x++)
1776 dx = (x - 15.5f) * (1.0f / 16.0f);
1777 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1778 a = bound(0, a, 255);
1779 pixels[y][x][0] = a;
1780 pixels[y][x][1] = a;
1781 pixels[y][x][2] = a;
1782 pixels[y][x][3] = 255;
1785 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, false);
1788 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1790 float dist = sqrt(x*x+y*y+z*z);
1791 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1792 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1793 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1796 static void R_Shadow_MakeTextures(void)
1799 float intensity, dist;
1801 R_Shadow_FreeShadowMaps();
1802 R_FreeTexturePool(&r_shadow_texturepool);
1803 r_shadow_texturepool = R_AllocTexturePool();
1804 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1805 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1806 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1807 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1808 for (x = 0;x <= ATTENTABLESIZE;x++)
1810 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1811 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1812 r_shadow_attentable[x] = bound(0, intensity, 1);
1814 // 1D gradient texture
1815 for (x = 0;x < ATTEN1DSIZE;x++)
1816 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1817 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1818 // 2D circle texture
1819 for (y = 0;y < ATTEN2DSIZE;y++)
1820 for (x = 0;x < ATTEN2DSIZE;x++)
1821 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);
1822 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1823 // 3D sphere texture
1824 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1826 for (z = 0;z < ATTEN3DSIZE;z++)
1827 for (y = 0;y < ATTEN3DSIZE;y++)
1828 for (x = 0;x < ATTEN3DSIZE;x++)
1829 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));
1830 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1833 r_shadow_attenuation3dtexture = NULL;
1836 R_Shadow_MakeTextures_MakeCorona();
1838 // Editor light sprites
1839 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1856 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1857 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1874 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1875 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1892 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1893 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1910 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1911 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1928 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1929 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1946 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1949 void R_Shadow_ValidateCvars(void)
1951 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1952 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1953 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1954 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1955 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1956 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1959 void R_Shadow_RenderMode_Begin(void)
1965 R_Shadow_ValidateCvars();
1967 if (!r_shadow_attenuation2dtexture
1968 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1969 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1970 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1971 R_Shadow_MakeTextures();
1974 R_Mesh_ResetTextureState();
1975 GL_BlendFunc(GL_ONE, GL_ZERO);
1976 GL_DepthRange(0, 1);
1977 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1979 GL_DepthMask(false);
1980 GL_Color(0, 0, 0, 1);
1981 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1983 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1985 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1987 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1988 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1990 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1992 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1993 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1997 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1998 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
2001 switch(vid.renderpath)
2003 case RENDERPATH_GL20:
2004 case RENDERPATH_D3D9:
2005 case RENDERPATH_D3D10:
2006 case RENDERPATH_D3D11:
2007 case RENDERPATH_SOFT:
2008 case RENDERPATH_GLES2:
2009 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
2011 case RENDERPATH_GL11:
2012 case RENDERPATH_GL13:
2013 case RENDERPATH_GLES1:
2014 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
2015 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
2016 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
2017 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
2018 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
2019 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
2021 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
2027 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
2028 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
2029 r_shadow_drawbuffer = drawbuffer;
2030 r_shadow_readbuffer = readbuffer;
2032 r_shadow_cullface_front = r_refdef.view.cullface_front;
2033 r_shadow_cullface_back = r_refdef.view.cullface_back;
2036 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
2038 rsurface.rtlight = rtlight;
2041 void R_Shadow_RenderMode_Reset(void)
2043 R_Mesh_ResetTextureState();
2044 R_Mesh_SetRenderTargets(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture, NULL, NULL, NULL);
2045 R_SetViewport(&r_refdef.view.viewport);
2046 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
2047 GL_DepthRange(0, 1);
2049 GL_DepthMask(false);
2050 GL_DepthFunc(GL_LEQUAL);
2051 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2052 r_refdef.view.cullface_front = r_shadow_cullface_front;
2053 r_refdef.view.cullface_back = r_shadow_cullface_back;
2054 GL_CullFace(r_refdef.view.cullface_back);
2055 GL_Color(1, 1, 1, 1);
2056 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2057 GL_BlendFunc(GL_ONE, GL_ZERO);
2058 R_SetupShader_Generic_NoTexture(false, false);
2059 r_shadow_usingshadowmap2d = false;
2060 r_shadow_usingshadowmaportho = false;
2061 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2064 void R_Shadow_ClearStencil(void)
2066 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2067 r_refdef.stats[r_stat_lights_clears]++;
2070 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2072 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2073 if (r_shadow_rendermode == mode)
2075 R_Shadow_RenderMode_Reset();
2076 GL_DepthFunc(GL_LESS);
2077 GL_ColorMask(0, 0, 0, 0);
2078 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2079 GL_CullFace(GL_NONE);
2080 R_SetupShader_DepthOrShadow(false, false, false); // FIXME test if we have a skeletal model?
2081 r_shadow_rendermode = mode;
2086 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2087 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2088 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2090 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2091 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2092 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2097 static void R_Shadow_MakeVSDCT(void)
2099 // maps to a 2x3 texture rectangle with normalized coordinates
2104 // stores abs(dir.xy), offset.xy/2.5
2105 unsigned char data[4*6] =
2107 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2108 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2109 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2110 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2111 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2112 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2114 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2117 static void R_Shadow_MakeShadowMap(int side, int size)
2119 switch (r_shadow_shadowmode)
2121 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2122 if (r_shadow_shadowmap2ddepthtexture) return;
2123 if (r_fb.usedepthtextures)
2125 r_shadow_shadowmap2ddepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), r_shadow_shadowmapdepthbits >= 24 ? (r_shadow_shadowmapsampler ? TEXTYPE_SHADOWMAP24_COMP : TEXTYPE_SHADOWMAP24_RAW) : (r_shadow_shadowmapsampler ? TEXTYPE_SHADOWMAP16_COMP : TEXTYPE_SHADOWMAP16_RAW), r_shadow_shadowmapsampler);
2126 r_shadow_shadowmap2ddepthbuffer = NULL;
2127 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2131 r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2132 r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
2133 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2141 static void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2143 float nearclip, farclip, bias;
2144 r_viewport_t viewport;
2147 float clearcolor[4];
2148 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2150 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2151 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2152 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2153 r_shadow_shadowmapside = side;
2154 r_shadow_shadowmapsize = size;
2156 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2157 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2158 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2159 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2161 // complex unrolled cube approach (more flexible)
2162 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2163 R_Shadow_MakeVSDCT();
2164 if (!r_shadow_shadowmap2ddepthtexture)
2165 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2166 fbo2d = r_shadow_fbo2d;
2167 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
2168 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
2169 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2171 R_Mesh_ResetTextureState();
2172 R_Shadow_RenderMode_Reset();
2173 if (r_shadow_shadowmap2ddepthbuffer)
2174 R_Mesh_SetRenderTargets(fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2176 R_Mesh_SetRenderTargets(fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2177 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2178 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2183 R_SetViewport(&viewport);
2184 flipped = (side & 1) ^ (side >> 2);
2185 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2186 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2187 if (r_shadow_shadowmap2ddepthbuffer)
2189 // completely different meaning than in depthtexture approach
2190 r_shadow_shadowmap_parameters[1] = 0;
2191 r_shadow_shadowmap_parameters[3] = -bias;
2193 Vector4Set(clearcolor, 1,1,1,1);
2194 if (r_shadow_shadowmap2ddepthbuffer)
2195 GL_ColorMask(1,1,1,1);
2197 GL_ColorMask(0,0,0,0);
2198 switch(vid.renderpath)
2200 case RENDERPATH_GL11:
2201 case RENDERPATH_GL13:
2202 case RENDERPATH_GL20:
2203 case RENDERPATH_SOFT:
2204 case RENDERPATH_GLES1:
2205 case RENDERPATH_GLES2:
2206 GL_CullFace(r_refdef.view.cullface_back);
2207 // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
2208 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2210 // get tightest scissor rectangle that encloses all viewports in the clear mask
2211 int x1 = clear & 0x15 ? 0 : size;
2212 int x2 = clear & 0x2A ? 2 * size : size;
2213 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2214 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2215 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2218 if (r_shadow_shadowmap2ddepthbuffer)
2219 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2221 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2224 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2226 case RENDERPATH_D3D9:
2227 case RENDERPATH_D3D10:
2228 case RENDERPATH_D3D11:
2229 // we invert the cull mode because we flip the projection matrix
2230 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2231 GL_CullFace(r_refdef.view.cullface_front);
2232 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2233 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2236 if (r_shadow_shadowmap2ddepthbuffer)
2237 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2239 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2245 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2247 R_Mesh_ResetTextureState();
2250 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2251 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2252 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2253 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2255 R_Shadow_RenderMode_Reset();
2256 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2258 GL_DepthFunc(GL_EQUAL);
2259 // do global setup needed for the chosen lighting mode
2260 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2261 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2262 r_shadow_usingshadowmap2d = shadowmapping;
2263 r_shadow_rendermode = r_shadow_lightingrendermode;
2264 // only draw light where this geometry was already rendered AND the
2265 // stencil is 128 (values other than this mean shadow)
2267 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2269 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2272 static const unsigned short bboxelements[36] =
2282 static const float bboxpoints[8][3] =
2294 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2297 float vertex3f[8*3];
2298 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2299 // do global setup needed for the chosen lighting mode
2300 R_Shadow_RenderMode_Reset();
2301 r_shadow_rendermode = r_shadow_lightingrendermode;
2302 R_EntityMatrix(&identitymatrix);
2303 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2304 // only draw light where this geometry was already rendered AND the
2305 // stencil is 128 (values other than this mean shadow)
2306 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2307 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
2308 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2310 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
2312 r_shadow_usingshadowmap2d = shadowmapping;
2314 // render the lighting
2315 R_SetupShader_DeferredLight(rsurface.rtlight);
2316 for (i = 0;i < 8;i++)
2317 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2318 GL_ColorMask(1,1,1,1);
2319 GL_DepthMask(false);
2320 GL_DepthRange(0, 1);
2321 GL_PolygonOffset(0, 0);
2323 GL_DepthFunc(GL_GREATER);
2324 GL_CullFace(r_refdef.view.cullface_back);
2325 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
2326 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2329 // these are temporary data per-frame, sorted and performed in a more
2330 // cache-friendly order than the original photons
2331 typedef struct r_shadow_bouncegrid_splatpath_s
2337 vec_t splatintensity;
2338 int remainingsplats;
2340 r_shadow_bouncegrid_splatpath_t;
2342 static void R_shadow_BounceGrid_AddSplatPath(vec3_t originalstart, vec3_t originalend, vec3_t color)
2352 r_shadow_bouncegrid_splatpath_t *path;
2354 // cull paths that fail R_CullBox in dynamic mode
2355 if (!r_shadow_bouncegrid_state.settings.staticmode
2356 && r_shadow_bouncegrid_culllightpaths.integer)
2358 vec3_t cullmins, cullmaxs;
2359 cullmins[0] = min(originalstart[0], originalend[0]) - r_shadow_bouncegrid_state.settings.spacing[0];
2360 cullmins[1] = min(originalstart[1], originalend[1]) - r_shadow_bouncegrid_state.settings.spacing[1];
2361 cullmins[2] = min(originalstart[2], originalend[2]) - r_shadow_bouncegrid_state.settings.spacing[2];
2362 cullmaxs[0] = max(originalstart[0], originalend[0]) + r_shadow_bouncegrid_state.settings.spacing[0];
2363 cullmaxs[1] = max(originalstart[1], originalend[1]) + r_shadow_bouncegrid_state.settings.spacing[1];
2364 cullmaxs[2] = max(originalstart[2], originalend[2]) + r_shadow_bouncegrid_state.settings.spacing[2];
2365 if (R_CullBox(cullmins, cullmaxs))
2369 // if the light path is going upward, reverse it - we always draw down.
2370 if (originalend[2] < originalstart[2])
2372 VectorCopy(originalend, start);
2373 VectorCopy(originalstart, end);
2377 VectorCopy(originalstart, start);
2378 VectorCopy(originalend, end);
2381 // transform to texture pixels
2382 start[0] = (start[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2383 start[1] = (start[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2384 start[2] = (start[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2385 end[0] = (end[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2386 end[1] = (end[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2387 end[2] = (end[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2389 // check if we need to grow the splatpaths array
2390 if (r_shadow_bouncegrid_state.maxsplatpaths <= r_shadow_bouncegrid_state.numsplatpaths)
2392 // double the limit, this will persist from frame to frame so we don't
2393 // make the same mistake each time
2394 r_shadow_bouncegrid_splatpath_t *newpaths;
2395 r_shadow_bouncegrid_state.maxsplatpaths *= 2;
2396 newpaths = (r_shadow_bouncegrid_splatpath_t *)R_FrameData_Alloc(sizeof(r_shadow_bouncegrid_splatpath_t) * r_shadow_bouncegrid_state.maxsplatpaths);
2397 if (r_shadow_bouncegrid_state.splatpaths)
2398 memcpy(newpaths, r_shadow_bouncegrid_state.splatpaths, r_shadow_bouncegrid_state.numsplatpaths * sizeof(r_shadow_bouncegrid_splatpath_t));
2399 r_shadow_bouncegrid_state.splatpaths = newpaths;
2402 // divide a series of splats along the length using the maximum axis
2403 VectorSubtract(end, start, diff);
2404 // pick the best axis to trace along
2406 if (diff[1]*diff[1] > diff[bestaxis]*diff[bestaxis])
2408 if (diff[2]*diff[2] > diff[bestaxis]*diff[bestaxis])
2410 len = fabs(diff[bestaxis]);
2412 numsplats = (int)(floor(len + 0.5f));
2414 numsplats = bound(0, numsplats, 1024);
2416 VectorSubtract(originalstart, originalend, originaldir);
2417 VectorNormalize(originaldir);
2419 path = r_shadow_bouncegrid_state.splatpaths + r_shadow_bouncegrid_state.numsplatpaths++;
2420 VectorCopy(start, path->point);
2421 VectorScale(diff, ilen, path->step);
2422 VectorCopy(color, path->splatcolor);
2423 VectorCopy(originaldir, path->splatdir);
2424 path->splatintensity = VectorLength(color);
2425 path->remainingsplats = numsplats;
2428 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
2430 qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
2437 // see if there are really any lights to render...
2438 if (enable && r_shadow_bouncegrid_static.integer)
2441 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2442 for (lightindex = 0;lightindex < range;lightindex++)
2444 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2445 if (!light || !(light->flags & flag))
2447 rtlight = &light->rtlight;
2448 // when static, we skip styled lights because they tend to change...
2449 if (rtlight->style > 0)
2451 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
2452 if (!VectorLength2(lightcolor))
2462 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
2464 // prevent any garbage in alignment padded areas as we'll be using memcmp
2465 memset(settings, 0, sizeof(*settings));
2467 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
2468 settings->staticmode = r_shadow_bouncegrid_static.integer != 0;
2469 settings->bounceanglediffuse = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
2470 settings->directionalshading = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
2471 settings->dlightparticlemultiplier = r_shadow_bouncegrid_dlightparticlemultiplier.value;
2472 settings->hitmodels = r_shadow_bouncegrid_hitmodels.integer != 0;
2473 settings->includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
2474 settings->lightradiusscale = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_lightradiusscale.value);
2475 settings->maxbounce = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_maxbounce.integer);
2476 settings->particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
2477 settings->particleintensity = r_shadow_bouncegrid_particleintensity.value * 16384.0f * (settings->directionalshading ? 4.0f : 1.0f) / (r_shadow_bouncegrid_spacing.value * r_shadow_bouncegrid_spacing.value);
2478 settings->maxphotons = r_shadow_bouncegrid_static.integer ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_maxphotons.integer;
2479 settings->intensityperphoton = r_shadow_bouncegrid_static.integer ? r_shadow_bouncegrid_static_intensityperphoton.integer : r_shadow_bouncegrid_intensityperphoton.integer;
2480 settings->spacing[0] = r_shadow_bouncegrid_spacing.value;
2481 settings->spacing[1] = r_shadow_bouncegrid_spacing.value;
2482 settings->spacing[2] = r_shadow_bouncegrid_spacing.value;
2483 settings->stablerandom = r_shadow_bouncegrid_stablerandom.integer;
2485 // bound the values for sanity
2486 settings->maxphotons = bound(1, settings->maxphotons, 25000000);
2487 settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
2488 settings->maxbounce = bound(0, settings->maxbounce, 16);
2489 settings->spacing[0] = bound(1, settings->spacing[0], 512);
2490 settings->spacing[1] = bound(1, settings->spacing[1], 512);
2491 settings->spacing[2] = bound(1, settings->spacing[2], 512);
2494 static void R_Shadow_BounceGrid_UpdateSpacing(void)
2505 r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
2507 // get the spacing values
2508 spacing[0] = settings->spacing[0];
2509 spacing[1] = settings->spacing[1];
2510 spacing[2] = settings->spacing[2];
2511 ispacing[0] = 1.0f / spacing[0];
2512 ispacing[1] = 1.0f / spacing[1];
2513 ispacing[2] = 1.0f / spacing[2];
2515 // calculate texture size enclosing entire world bounds at the spacing
2516 if (r_refdef.scene.worldmodel)
2518 VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
2519 VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
2523 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
2524 VectorSet(maxs, 1048576.0f, 1048576.0f, 1048576.0f);
2526 VectorSubtract(maxs, mins, size);
2527 // now we can calculate the resolution we want
2528 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2529 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2530 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2531 // figure out the exact texture size (honoring power of 2 if required)
2532 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2533 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2534 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2535 if (vid.support.arb_texture_non_power_of_two)
2537 resolution[0] = c[0];
2538 resolution[1] = c[1];
2539 resolution[2] = c[2];
2543 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2544 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2545 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2547 size[0] = spacing[0] * resolution[0];
2548 size[1] = spacing[1] * resolution[1];
2549 size[2] = spacing[2] * resolution[2];
2551 // if dynamic we may or may not want to use the world bounds
2552 // if the dynamic size is smaller than the world bounds, use it instead
2553 if (!settings->staticmode && (r_shadow_bouncegrid_x.integer * r_shadow_bouncegrid_y.integer * r_shadow_bouncegrid_z.integer < resolution[0] * resolution[1] * resolution[2]))
2555 // we know the resolution we want
2556 c[0] = r_shadow_bouncegrid_x.integer;
2557 c[1] = r_shadow_bouncegrid_y.integer;
2558 c[2] = r_shadow_bouncegrid_z.integer;
2559 // now we can calculate the texture size (power of 2 if required)
2560 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2561 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2562 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2563 if (vid.support.arb_texture_non_power_of_two)
2565 resolution[0] = c[0];
2566 resolution[1] = c[1];
2567 resolution[2] = c[2];
2571 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2572 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2573 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2575 size[0] = spacing[0] * resolution[0];
2576 size[1] = spacing[1] * resolution[1];
2577 size[2] = spacing[2] * resolution[2];
2578 // center the rendering on the view
2579 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2580 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2581 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2584 // recalculate the maxs in case the resolution was not satisfactory
2585 VectorAdd(mins, size, maxs);
2587 // check if this changed the texture size
2588 r_shadow_bouncegrid_state.createtexture = !(r_shadow_bouncegrid_state.texture && r_shadow_bouncegrid_state.resolution[0] == resolution[0] && r_shadow_bouncegrid_state.resolution[1] == resolution[1] && r_shadow_bouncegrid_state.resolution[2] == resolution[2] && r_shadow_bouncegrid_state.directional == r_shadow_bouncegrid_state.settings.directionalshading);
2589 r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
2590 VectorCopy(mins, r_shadow_bouncegrid_state.mins);
2591 VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
2592 VectorCopy(size, r_shadow_bouncegrid_state.size);
2593 VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
2594 VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
2595 VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
2597 // reallocate pixels for this update if needed...
2598 r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
2599 r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
2600 r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
2601 numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
2602 if (r_shadow_bouncegrid_state.numpixels != numpixels || !r_shadow_bouncegrid_state.pixels || !r_shadow_bouncegrid_state.highpixels)
2604 if (r_shadow_bouncegrid_state.texture)
2606 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2607 r_shadow_bouncegrid_state.texture = NULL;
2609 r_shadow_bouncegrid_state.pixels = (unsigned char *)Mem_Realloc(r_main_mempool, r_shadow_bouncegrid_state.pixels, numpixels * sizeof(unsigned char[4]));
2610 r_shadow_bouncegrid_state.highpixels = (float *)Mem_Realloc(r_main_mempool, r_shadow_bouncegrid_state.highpixels, numpixels * sizeof(float[4]));
2611 r_shadow_bouncegrid_state.numpixels = numpixels;
2614 // update the bouncegrid matrix to put it in the world properly
2615 memset(m, 0, sizeof(m));
2616 m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
2617 m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
2618 m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
2619 m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
2620 m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
2621 m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
2623 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
2626 #define MAXBOUNCEGRIDPARTICLESPERLIGHT 1048576
2628 // enumerate world rtlights and sum the overall amount of light in the world,
2629 // from that we can calculate a scaling factor to fairly distribute photons
2630 // to all the lights
2632 // this modifies rtlight->photoncolor and rtlight->photons
2633 static void R_Shadow_BounceGrid_AssignPhotons(r_shadow_bouncegrid_settings_t *settings, unsigned int range, unsigned int range1, unsigned int range2, int flag, float *photonscaling)
2635 float normalphotonscaling;
2636 float maxphotonscaling;
2637 float photoncount = 0.0f;
2638 float lightintensity;
2644 unsigned int lightindex;
2647 for (lightindex = 0;lightindex < range2;lightindex++)
2649 if (lightindex < range)
2651 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2654 rtlight = &light->rtlight;
2655 VectorClear(rtlight->photoncolor);
2656 rtlight->photons = 0;
2657 if (!(light->flags & flag))
2659 if (settings->staticmode)
2661 // when static, we skip styled lights because they tend to change...
2662 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2668 rtlight = r_refdef.scene.lights[lightindex - range];
2669 VectorClear(rtlight->photoncolor);
2670 rtlight->photons = 0;
2672 // draw only visible lights (major speedup)
2673 radius = rtlight->radius * settings->lightradiusscale;
2674 cullmins[0] = rtlight->shadoworigin[0] - radius;
2675 cullmins[1] = rtlight->shadoworigin[1] - radius;
2676 cullmins[2] = rtlight->shadoworigin[2] - radius;
2677 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2678 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2679 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2680 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2681 if (!settings->staticmode)
2683 if (R_CullBox(cullmins, cullmaxs))
2685 if (r_refdef.scene.worldmodel
2686 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2687 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2689 if (w * VectorLength2(rtlight->color) == 0.0f)
2692 // a light that does not emit any light before style is applied, can be
2693 // skipped entirely (it may just be a corona)
2694 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2696 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2697 VectorScale(rtlight->color, w, rtlight->photoncolor);
2698 // skip lights that will emit no photons
2699 if (!VectorLength2(rtlight->photoncolor))
2701 // shoot particles from this light
2702 // use a calculation for the number of particles that will not
2703 // vary with lightstyle, otherwise we get randomized particle
2704 // distribution, the seeded random is only consistent for a
2705 // consistent number of particles on this light...
2706 s = rtlight->radius;
2707 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2708 if (lightindex >= range)
2709 lightintensity *= settings->dlightparticlemultiplier;
2710 rtlight->photons = bound(0.0f, lightintensity * s * s, MAXBOUNCEGRIDPARTICLESPERLIGHT);
2711 photoncount += rtlight->photons;
2712 // if the lightstyle happens to be off right now, we can skip actually
2713 // firing the photons, but we did have to count them in the total.
2714 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2715 // rtlight->photons = 0;
2717 // the user provided an intensityperphoton value which we try to use
2718 // if that results in too many photons to shoot this frame, then we cap it
2719 // which causes photons to appear/disappear from frame to frame, so we don't
2720 // like doing that in the typical case
2721 normalphotonscaling = 1.0f / max(0.0001f, r_shadow_bouncegrid_intensityperphoton.value);
2722 maxphotonscaling = (float)settings->maxphotons / max(1, photoncount);
2723 *photonscaling = min(normalphotonscaling, maxphotonscaling);
2726 static void R_Shadow_BounceGrid_ClearPixels(void)
2729 for (pixelband = 0;pixelband < r_shadow_bouncegrid_state.pixelbands;pixelband++)
2732 memset(r_shadow_bouncegrid_state.pixels + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
2734 memset(r_shadow_bouncegrid_state.pixels + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
2736 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2739 static int R_Shadow_BounceGrid_SplatPathCompare(const void *pa, const void *pb)
2741 r_shadow_bouncegrid_splatpath_t *a = (r_shadow_bouncegrid_splatpath_t *)pa;
2742 r_shadow_bouncegrid_splatpath_t *b = (r_shadow_bouncegrid_splatpath_t *)pb;
2743 // we only really care about sorting by Z
2744 if (a->point[2] < b->point[2])
2746 if (a->point[2] > b->point[2])
2751 static void R_Shadow_BounceGrid_PerformSplats(void)
2753 r_shadow_bouncegrid_splatpath_t *splatpaths = r_shadow_bouncegrid_state.splatpaths;
2754 r_shadow_bouncegrid_splatpath_t *splatpath;
2755 unsigned char *pixel;
2756 unsigned char *pixels = r_shadow_bouncegrid_state.pixels;
2758 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2759 int numsplatpaths = r_shadow_bouncegrid_state.numsplatpaths;
2764 float texlerp[2][3];
2765 float splatcolor[32];
2766 float pixelweight[8];
2772 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2774 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2778 // hush warnings about uninitialized data - pixelbands doesn't change but...
2779 memset(splatcolor, 0, sizeof(splatcolor));
2781 // we use this a lot, so get a local copy
2782 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2784 // sort the splats before we execute them, to reduce cache misses
2785 if (r_shadow_bouncegrid_sortlightpaths.integer)
2786 qsort(splatpaths, numsplatpaths, sizeof(*splatpaths), R_Shadow_BounceGrid_SplatPathCompare);
2788 splatpath = splatpaths;
2789 for (splatindex = 0;splatindex < numsplatpaths;splatindex++, splatpath++)
2792 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2793 // accumulate average shotcolor
2794 VectorCopy(splatpath->splatdir, dir);
2795 splatcolor[ 0] = splatpath->splatcolor[0];
2796 splatcolor[ 1] = splatpath->splatcolor[1];
2797 splatcolor[ 2] = splatpath->splatcolor[2];
2798 splatcolor[ 3] = 0.0f;
2801 // store bentnormal in case the shader has a use for it,
2802 // bentnormal is an intensity-weighted average of the directions,
2803 // and will be normalized on conversion to texture pixels.
2804 splatcolor[ 4] = dir[0] * splatpath->splatintensity;
2805 splatcolor[ 5] = dir[1] * splatpath->splatintensity;
2806 splatcolor[ 6] = dir[2] * splatpath->splatintensity;
2807 splatcolor[ 7] = splatpath->splatintensity;
2808 // for each color component (R, G, B) calculate the amount that a
2809 // direction contributes
2810 splatcolor[ 8] = splatcolor[0] * max(0.0f, dir[0]);
2811 splatcolor[ 9] = splatcolor[0] * max(0.0f, dir[1]);
2812 splatcolor[10] = splatcolor[0] * max(0.0f, dir[2]);
2813 splatcolor[11] = 0.0f;
2814 splatcolor[12] = splatcolor[1] * max(0.0f, dir[0]);
2815 splatcolor[13] = splatcolor[1] * max(0.0f, dir[1]);
2816 splatcolor[14] = splatcolor[1] * max(0.0f, dir[2]);
2817 splatcolor[15] = 0.0f;
2818 splatcolor[16] = splatcolor[2] * max(0.0f, dir[0]);
2819 splatcolor[17] = splatcolor[2] * max(0.0f, dir[1]);
2820 splatcolor[18] = splatcolor[2] * max(0.0f, dir[2]);
2821 splatcolor[19] = 0.0f;
2822 // and do the same for negative directions
2823 splatcolor[20] = splatcolor[0] * max(0.0f, -dir[0]);
2824 splatcolor[21] = splatcolor[0] * max(0.0f, -dir[1]);
2825 splatcolor[22] = splatcolor[0] * max(0.0f, -dir[2]);
2826 splatcolor[23] = 0.0f;
2827 splatcolor[24] = splatcolor[1] * max(0.0f, -dir[0]);
2828 splatcolor[25] = splatcolor[1] * max(0.0f, -dir[1]);
2829 splatcolor[26] = splatcolor[1] * max(0.0f, -dir[2]);
2830 splatcolor[27] = 0.0f;
2831 splatcolor[28] = splatcolor[2] * max(0.0f, -dir[0]);
2832 splatcolor[29] = splatcolor[2] * max(0.0f, -dir[1]);
2833 splatcolor[30] = splatcolor[2] * max(0.0f, -dir[2]);
2834 splatcolor[31] = 0.0f;
2836 // calculate the number of steps we need to traverse this distance
2837 VectorCopy(splatpath->point, steppos);
2838 VectorCopy(splatpath->step, stepdelta);
2839 numsteps = splatpath->remainingsplats;
2840 for (step = 0;step < numsteps;step++)
2842 r_refdef.stats[r_stat_bouncegrid_splats]++;
2843 // figure out which texture pixels this is in
2844 texlerp[1][0] = steppos[0] - 0.5f;
2845 texlerp[1][1] = steppos[1] - 0.5f;
2846 texlerp[1][2] = steppos[2] - 0.5f;
2847 tex[0] = (int)floor(texlerp[1][0]);
2848 tex[1] = (int)floor(texlerp[1][1]);
2849 tex[2] = (int)floor(texlerp[1][2]);
2853 && tex[0] < resolution[0] - 2
2854 && tex[1] < resolution[1] - 2
2855 && tex[2] < resolution[2] - 2)
2857 // it is within bounds... do the real work now
2858 // calculate the lerp factors
2859 texlerp[1][0] -= tex[0];
2860 texlerp[1][1] -= tex[1];
2861 texlerp[1][2] -= tex[2];
2862 texlerp[0][0] = 1.0f - texlerp[1][0];
2863 texlerp[0][1] = 1.0f - texlerp[1][1];
2864 texlerp[0][2] = 1.0f - texlerp[1][2];
2865 // calculate individual pixel indexes and weights
2866 pixelindex[0] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[0] = (texlerp[0][0]*texlerp[0][1]*texlerp[0][2]);
2867 pixelindex[1] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0]+1);pixelweight[1] = (texlerp[1][0]*texlerp[0][1]*texlerp[0][2]);
2868 pixelindex[2] = (((tex[2] )*resolution[1]+tex[1]+1)*resolution[0]+tex[0] );pixelweight[2] = (texlerp[0][0]*texlerp[1][1]*texlerp[0][2]);
2869 pixelindex[3] = (((tex[2] )*resolution[1]+tex[1]+1)*resolution[0]+tex[0]+1);pixelweight[3] = (texlerp[1][0]*texlerp[1][1]*texlerp[0][2]);
2870 pixelindex[4] = (((tex[2]+1)*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[4] = (texlerp[0][0]*texlerp[0][1]*texlerp[1][2]);
2871 pixelindex[5] = (((tex[2]+1)*resolution[1]+tex[1] )*resolution[0]+tex[0]+1);pixelweight[5] = (texlerp[1][0]*texlerp[0][1]*texlerp[1][2]);
2872 pixelindex[6] = (((tex[2]+1)*resolution[1]+tex[1]+1)*resolution[0]+tex[0] );pixelweight[6] = (texlerp[0][0]*texlerp[1][1]*texlerp[1][2]);
2873 pixelindex[7] = (((tex[2]+1)*resolution[1]+tex[1]+1)*resolution[0]+tex[0]+1);pixelweight[7] = (texlerp[1][0]*texlerp[1][1]*texlerp[1][2]);
2874 // update the 8 pixels...
2875 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2877 for (corner = 0;corner < 8;corner++)
2879 // calculate address for pixel
2880 w = pixelweight[corner];
2881 pixel = pixels + 4 * pixelindex[corner] + pixelband * pixelsperband * 4;
2882 highpixel = highpixels + 4 * pixelindex[corner] + pixelband * pixelsperband * 4;
2883 // add to the high precision pixel color
2884 highpixel[0] += (splatcolor[pixelband*4+0]*w);
2885 highpixel[1] += (splatcolor[pixelband*4+1]*w);
2886 highpixel[2] += (splatcolor[pixelband*4+2]*w);
2887 highpixel[3] += (splatcolor[pixelband*4+3]*w);
2888 // flag the low precision pixel as needing to be updated
2890 // advance to next band of coefficients
2891 //pixel += pixelsperband*4;
2892 //highpixel += pixelsperband*4;
2896 VectorAdd(steppos, stepdelta, steppos);
2901 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
2903 unsigned char *pixels = r_shadow_bouncegrid_state.pixels;
2904 unsigned char *pixel;
2905 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2907 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2908 unsigned int pixelband;
2909 unsigned int x, y, z;
2911 unsigned int resolution[3];
2913 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2914 // generate pixels array from highpixels array
2916 // skip first and last columns, rows, and layers as these are blank
2918 // the pixel[3] value was deliberately written along with highpixels
2919 // updates, so we can use it to detect only pixels that need to be
2920 // converted, the rest were already memset to neutral values.
2921 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2923 for (z = 1;z < resolution[2]-1;z++)
2925 for (y = 1;y < resolution[1]-1;y++)
2928 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2929 pixel = pixels + 4*index;
2930 highpixel = highpixels + 4*index;
2931 for (;x < resolution[0]-1;x++, pixel += 4, highpixel += 4)
2933 // only convert pixels that were hit by photons
2934 if (pixel[3] == 255)
2936 // normalize the bentnormal...
2939 VectorNormalize(highpixel);
2940 c[0] = (int)(highpixel[0]*128.0f+128.0f);
2941 c[1] = (int)(highpixel[1]*128.0f+128.0f);
2942 c[2] = (int)(highpixel[2]*128.0f+128.0f);
2943 c[3] = (int)(highpixel[3]*128.0f+128.0f);
2947 c[0] = (int)(highpixel[0]*256.0f);
2948 c[1] = (int)(highpixel[1]*256.0f);
2949 c[2] = (int)(highpixel[2]*256.0f);
2950 c[3] = (int)(highpixel[3]*256.0f);
2952 pixel[2] = (unsigned char)bound(0, c[0], 255);
2953 pixel[1] = (unsigned char)bound(0, c[1], 255);
2954 pixel[0] = (unsigned char)bound(0, c[2], 255);
2955 pixel[3] = (unsigned char)bound(0, c[3], 255);
2962 if (!r_shadow_bouncegrid_state.createtexture)
2963 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixels, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2966 if (r_shadow_bouncegrid_state.texture)
2967 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2968 r_shadow_bouncegrid_state.texture = R_LoadTexture3D(r_shadow_texturepool, "bouncegrid", resolution[0], resolution[1], resolution[2]*pixelbands, pixels, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, 0, NULL);
2970 r_shadow_bouncegrid_state.lastupdatetime = realtime;
2973 static void R_Shadow_BounceGrid_TracePhotons(r_shadow_bouncegrid_settings_t settings, unsigned int range, unsigned int range1, unsigned int range2, float photonscaling, int flag)
2977 int hitsupercontentsmask;
2982 //trace_t cliptrace2;
2983 //trace_t cliptrace3;
2984 unsigned int lightindex;
2985 unsigned int seed = (unsigned int)(realtime * 1000.0f);
2987 vec3_t baseshotcolor;
2996 // we'll need somewhere to store these
2997 r_shadow_bouncegrid_state.numsplatpaths = 0;
2998 r_shadow_bouncegrid_state.splatpaths = (r_shadow_bouncegrid_splatpath_t *)R_FrameData_Alloc(sizeof(r_shadow_bouncegrid_splatpath_t) * r_shadow_bouncegrid_state.maxsplatpaths);
3000 // figure out what we want to interact with
3001 if (settings.hitmodels)
3002 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;// | SUPERCONTENTS_LIQUIDSMASK;
3004 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
3005 maxbounce = settings.maxbounce;
3007 for (lightindex = 0;lightindex < range2;lightindex++)
3009 if (lightindex < range)
3011 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3014 rtlight = &light->rtlight;
3017 rtlight = r_refdef.scene.lights[lightindex - range];
3018 // note that this code used to keep track of residual photons and
3019 // distribute them evenly to achieve exactly a desired photon count,
3020 // but that caused unwanted flickering in dynamic mode
3021 shootparticles = (int)floor(rtlight->photons * photonscaling);
3022 // skip if we won't be shooting any photons
3023 if (!shootparticles)
3025 radius = rtlight->radius * settings.lightradiusscale;
3026 s = settings.particleintensity / shootparticles;
3027 VectorScale(rtlight->photoncolor, s, baseshotcolor);
3028 r_refdef.stats[r_stat_bouncegrid_lights]++;
3029 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
3030 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
3032 if (settings.stablerandom > 0)
3033 seed = lightindex * 11937 + shotparticles;
3034 VectorCopy(baseshotcolor, shotcolor);
3035 VectorCopy(rtlight->shadoworigin, clipstart);
3036 if (settings.stablerandom < 0)
3037 VectorRandom(clipend);
3039 VectorCheeseRandom(clipend);
3040 VectorMA(clipstart, radius, clipend, clipend);
3041 for (bouncecount = 0;;bouncecount++)
3043 r_refdef.stats[r_stat_bouncegrid_traces]++;
3044 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
3045 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
3046 if (settings.staticmode)
3048 // static mode fires a LOT of rays but none of them are identical, so they are not cached
3049 cliptrace = CL_TraceLine(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), NULL, hitsupercontentsmask, collision_extendmovelength.value, true, false, NULL, true, true);
3053 // dynamic mode fires many rays and most will match the cache from the previous frame
3054 cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask);
3056 if (bouncecount > 0 || settings.includedirectlighting)
3059 VectorCopy(cliptrace.endpos, hitpos);
3060 R_shadow_BounceGrid_AddSplatPath(clipstart, hitpos, shotcolor);
3062 if (cliptrace.fraction >= 1.0f)
3064 r_refdef.stats[r_stat_bouncegrid_hits]++;
3065 if (bouncecount >= maxbounce)
3067 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
3068 // also clamp the resulting color to never add energy, even if the user requests extreme values
3069 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
3070 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
3072 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
3073 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
3074 surfcolor[0] = min(surfcolor[0], 1.0f);
3075 surfcolor[1] = min(surfcolor[1], 1.0f);
3076 surfcolor[2] = min(surfcolor[2], 1.0f);
3077 VectorMultiply(shotcolor, surfcolor, shotcolor);
3078 if (VectorLength2(baseshotcolor) == 0.0f)
3080 r_refdef.stats[r_stat_bouncegrid_bounces]++;
3081 if (settings.bounceanglediffuse)
3083 // random direction, primarily along plane normal
3084 s = VectorDistance(cliptrace.endpos, clipend);
3085 if (settings.stablerandom < 0)
3086 VectorRandom(clipend);
3088 VectorCheeseRandom(clipend);
3089 VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
3090 VectorNormalize(clipend);
3091 VectorScale(clipend, s, clipend);
3095 // reflect the remaining portion of the line across plane normal
3096 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
3097 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
3099 // calculate the new line start and end
3100 VectorCopy(cliptrace.endpos, clipstart);
3101 VectorAdd(clipstart, clipend, clipend);
3107 void R_Shadow_UpdateBounceGridTexture(void)
3109 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3110 r_shadow_bouncegrid_settings_t settings;
3111 qboolean enable = false;
3112 qboolean settingschanged;
3113 unsigned int range; // number of world lights
3114 unsigned int range1; // number of dynamic lights (or zero if disabled)
3115 unsigned int range2; // range+range1
3116 float photonscaling;
3118 enable = R_Shadow_BounceGrid_CheckEnable(flag);
3120 R_Shadow_BounceGrid_GenerateSettings(&settings);
3122 // changing intensity does not require an update
3123 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
3125 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
3127 // when settings change, we free everything as it is just simpler that way.
3128 if (settingschanged || !enable)
3130 // not enabled, make sure we free anything we don't need anymore.
3131 if (r_shadow_bouncegrid_state.texture)
3133 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3134 r_shadow_bouncegrid_state.texture = NULL;
3136 if (r_shadow_bouncegrid_state.pixels)
3137 Mem_Free(r_shadow_bouncegrid_state.pixels);
3138 r_shadow_bouncegrid_state.pixels = NULL;
3139 if (r_shadow_bouncegrid_state.highpixels)
3140 Mem_Free(r_shadow_bouncegrid_state.highpixels);
3141 r_shadow_bouncegrid_state.highpixels = NULL;
3142 r_shadow_bouncegrid_state.numpixels = 0;
3143 r_shadow_bouncegrid_state.directional = false;
3149 // if all the settings seem identical to the previous update, return
3150 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_updateinterval.value) && !settingschanged)
3153 // store the new settings
3154 r_shadow_bouncegrid_state.settings = settings;
3156 R_Shadow_BounceGrid_UpdateSpacing();
3158 // get the range of light numbers we'll be looping over:
3159 // range = static lights
3160 // range1 = dynamic lights (optional)
3161 // range2 = range + range1
3162 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3163 range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
3164 range2 = range + range1;
3166 // calculate weighting factors for distributing photons among the lights
3167 R_Shadow_BounceGrid_AssignPhotons(&settings, range, range1, range2, flag, &photonscaling);
3169 // trace the photons from lights and accumulate illumination
3170 R_Shadow_BounceGrid_TracePhotons(settings, range, range1, range2, photonscaling, flag);
3172 // clear the pixels[] and highpixels[] arrays, it is important that we
3173 // clear pixels[] now because we do tricks with marking pixels as needing
3174 // conversion, even though the source of truth data is in highpixels[]
3175 R_Shadow_BounceGrid_ClearPixels();
3177 // sort and accumulate the light splatting in the texture
3178 R_Shadow_BounceGrid_PerformSplats();
3180 // convert the pixels that were marked and upload the texture
3181 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
3184 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
3186 R_Shadow_RenderMode_Reset();
3187 GL_BlendFunc(GL_ONE, GL_ONE);
3188 GL_DepthRange(0, 1);
3189 GL_DepthTest(r_showshadowvolumes.integer < 2);
3190 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
3191 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
3192 GL_CullFace(GL_NONE);
3193 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
3196 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
3198 R_Shadow_RenderMode_Reset();
3199 GL_BlendFunc(GL_ONE, GL_ONE);
3200 GL_DepthRange(0, 1);
3201 GL_DepthTest(r_showlighting.integer < 2);
3202 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
3204 GL_DepthFunc(GL_EQUAL);
3205 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
3206 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
3209 void R_Shadow_RenderMode_End(void)
3211 R_Shadow_RenderMode_Reset();
3212 R_Shadow_RenderMode_ActiveLight(NULL);
3214 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3215 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3218 int bboxedges[12][2] =
3237 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
3239 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
3241 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
3242 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
3243 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
3244 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
3247 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
3248 return true; // invisible
3249 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
3250 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
3251 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
3252 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
3253 r_refdef.stats[r_stat_lights_scissored]++;
3257 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
3260 const float *vertex3f;
3261 const float *normal3f;
3263 float dist, dot, distintensity, shadeintensity, v[3], n[3];
3264 switch (r_shadow_rendermode)
3266 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3267 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3268 if (VectorLength2(diffusecolor) > 0)
3270 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
3272 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3273 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3274 if ((dot = DotProduct(n, v)) < 0)
3276 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3277 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
3280 VectorCopy(ambientcolor, color4f);
3281 if (r_refdef.fogenabled)
3284 f = RSurf_FogVertex(vertex3f);
3285 VectorScale(color4f, f, color4f);
3292 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3294 VectorCopy(ambientcolor, color4f);
3295 if (r_refdef.fogenabled)
3298 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3299 f = RSurf_FogVertex(vertex3f);
3300 VectorScale(color4f + 4*i, f, color4f);
3306 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3307 if (VectorLength2(diffusecolor) > 0)
3309 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
3311 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3312 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3314 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3315 if ((dot = DotProduct(n, v)) < 0)
3317 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3318 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3319 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3320 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3324 color4f[0] = ambientcolor[0] * distintensity;
3325 color4f[1] = ambientcolor[1] * distintensity;
3326 color4f[2] = ambientcolor[2] * distintensity;
3328 if (r_refdef.fogenabled)
3331 f = RSurf_FogVertex(vertex3f);
3332 VectorScale(color4f, f, color4f);
3336 VectorClear(color4f);
3342 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3344 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3345 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3347 color4f[0] = ambientcolor[0] * distintensity;
3348 color4f[1] = ambientcolor[1] * distintensity;
3349 color4f[2] = ambientcolor[2] * distintensity;
3350 if (r_refdef.fogenabled)
3353 f = RSurf_FogVertex(vertex3f);
3354 VectorScale(color4f, f, color4f);
3358 VectorClear(color4f);
3363 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3364 if (VectorLength2(diffusecolor) > 0)
3366 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
3368 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3369 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3371 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3372 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3373 if ((dot = DotProduct(n, v)) < 0)
3375 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3376 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3377 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3378 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3382 color4f[0] = ambientcolor[0] * distintensity;
3383 color4f[1] = ambientcolor[1] * distintensity;
3384 color4f[2] = ambientcolor[2] * distintensity;
3386 if (r_refdef.fogenabled)
3389 f = RSurf_FogVertex(vertex3f);
3390 VectorScale(color4f, f, color4f);
3394 VectorClear(color4f);
3400 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3402 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3403 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3405 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3406 color4f[0] = ambientcolor[0] * distintensity;
3407 color4f[1] = ambientcolor[1] * distintensity;
3408 color4f[2] = ambientcolor[2] * distintensity;
3409 if (r_refdef.fogenabled)
3412 f = RSurf_FogVertex(vertex3f);
3413 VectorScale(color4f, f, color4f);
3417 VectorClear(color4f);
3427 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3429 // used to display how many times a surface is lit for level design purposes
3430 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3431 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3435 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
3437 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3438 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
3442 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3449 int newnumtriangles;
3453 int maxtriangles = 1024;
3454 int newelements[1024*3];
3455 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3456 for (renders = 0;renders < 4;renders++)
3461 newnumtriangles = 0;
3463 // due to low fillrate on the cards this vertex lighting path is
3464 // designed for, we manually cull all triangles that do not
3465 // contain a lit vertex
3466 // this builds batches of triangles from multiple surfaces and
3467 // renders them at once
3468 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3470 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3472 if (newnumtriangles)
3474 newfirstvertex = min(newfirstvertex, e[0]);
3475 newlastvertex = max(newlastvertex, e[0]);
3479 newfirstvertex = e[0];
3480 newlastvertex = e[0];
3482 newfirstvertex = min(newfirstvertex, e[1]);
3483 newlastvertex = max(newlastvertex, e[1]);
3484 newfirstvertex = min(newfirstvertex, e[2]);
3485 newlastvertex = max(newlastvertex, e[2]);
3491 if (newnumtriangles >= maxtriangles)
3493 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3494 newnumtriangles = 0;
3500 if (newnumtriangles >= 1)
3502 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3505 // if we couldn't find any lit triangles, exit early
3508 // now reduce the intensity for the next overbright pass
3509 // we have to clamp to 0 here incase the drivers have improper
3510 // handling of negative colors
3511 // (some old drivers even have improper handling of >1 color)
3513 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3515 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3517 c[0] = max(0, c[0] - 1);
3518 c[1] = max(0, c[1] - 1);
3519 c[2] = max(0, c[2] - 1);
3531 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
3533 // OpenGL 1.1 path (anything)
3534 float ambientcolorbase[3], diffusecolorbase[3];
3535 float ambientcolorpants[3], diffusecolorpants[3];
3536 float ambientcolorshirt[3], diffusecolorshirt[3];
3537 const float *surfacecolor = rsurface.texture->dlightcolor;
3538 const float *surfacepants = rsurface.colormap_pantscolor;
3539 const float *surfaceshirt = rsurface.colormap_shirtcolor;
3540 rtexture_t *basetexture = rsurface.texture->basetexture;
3541 rtexture_t *pantstexture = rsurface.texture->pantstexture;
3542 rtexture_t *shirttexture = rsurface.texture->shirttexture;
3543 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3544 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3545 ambientscale *= 2 * r_refdef.view.colorscale;
3546 diffusescale *= 2 * r_refdef.view.colorscale;
3547 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3548 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3549 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3550 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3551 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3552 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
3553 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3554 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
3555 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3556 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
3557 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
3558 R_Mesh_TexBind(0, basetexture);
3559 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
3560 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
3561 switch(r_shadow_rendermode)
3563 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3564 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
3565 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3566 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3567 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3569 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3570 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
3571 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
3572 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
3573 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3575 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3576 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
3577 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3578 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3579 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3581 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3586 //R_Mesh_TexBind(0, basetexture);
3587 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
3590 R_Mesh_TexBind(0, pantstexture);
3591 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
3595 R_Mesh_TexBind(0, shirttexture);
3596 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
3600 extern cvar_t gl_lightmaps;
3601 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3603 float ambientscale, diffusescale, specularscale;
3605 float lightcolor[3];
3606 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
3607 ambientscale = rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient;
3608 diffusescale = rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient);
3609 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3610 if (!r_shadow_usenormalmap.integer)
3612 ambientscale += 1.0f * diffusescale;
3616 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
3618 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
3621 VectorNegate(lightcolor, lightcolor);
3622 GL_BlendEquationSubtract(true);
3624 RSurf_SetupDepthAndCulling();
3625 switch (r_shadow_rendermode)
3627 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3628 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3629 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
3631 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3632 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
3634 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3635 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3636 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3637 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3638 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
3641 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3645 GL_BlendEquationSubtract(false);
3648 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)
3650 matrix4x4_t tempmatrix = *matrix;
3651 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3653 // if this light has been compiled before, free the associated data
3654 R_RTLight_Uncompile(rtlight);
3656 // clear it completely to avoid any lingering data
3657 memset(rtlight, 0, sizeof(*rtlight));
3659 // copy the properties
3660 rtlight->matrix_lighttoworld = tempmatrix;
3661 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3662 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3663 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3664 VectorCopy(color, rtlight->color);
3665 rtlight->cubemapname[0] = 0;
3666 if (cubemapname && cubemapname[0])
3667 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3668 rtlight->shadow = shadow;
3669 rtlight->corona = corona;
3670 rtlight->style = style;
3671 rtlight->isstatic = isstatic;
3672 rtlight->coronasizescale = coronasizescale;
3673 rtlight->ambientscale = ambientscale;
3674 rtlight->diffusescale = diffusescale;
3675 rtlight->specularscale = specularscale;
3676 rtlight->flags = flags;
3678 // compute derived data
3679 //rtlight->cullradius = rtlight->radius;
3680 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3681 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3682 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3683 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3684 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3685 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3686 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3689 // compiles rtlight geometry
3690 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3691 void R_RTLight_Compile(rtlight_t *rtlight)
3694 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3695 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3696 entity_render_t *ent = r_refdef.scene.worldentity;
3697 dp_model_t *model = r_refdef.scene.worldmodel;
3698 unsigned char *data;
3701 // compile the light
3702 rtlight->compiled = true;
3703 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3704 rtlight->static_numleafs = 0;
3705 rtlight->static_numleafpvsbytes = 0;
3706 rtlight->static_leaflist = NULL;
3707 rtlight->static_leafpvs = NULL;
3708 rtlight->static_numsurfaces = 0;
3709 rtlight->static_surfacelist = NULL;
3710 rtlight->static_shadowmap_receivers = 0x3F;
3711 rtlight->static_shadowmap_casters = 0x3F;
3712 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3713 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3714 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3715 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3716 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3717 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3719 if (model && model->GetLightInfo)
3721 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3722 r_shadow_compilingrtlight = rtlight;
3723 R_FrameData_SetMark();
3724 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);
3725 R_FrameData_ReturnToMark();
3726 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3727 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3728 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3729 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3730 rtlight->static_numsurfaces = numsurfaces;
3731 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3732 rtlight->static_numleafs = numleafs;
3733 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3734 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3735 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3736 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3737 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3738 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3739 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3740 if (rtlight->static_numsurfaces)
3741 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3742 if (rtlight->static_numleafs)
3743 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3744 if (rtlight->static_numleafpvsbytes)
3745 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3746 if (rtlight->static_numshadowtrispvsbytes)
3747 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3748 if (rtlight->static_numlighttrispvsbytes)
3749 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3750 R_FrameData_SetMark();
3751 switch (rtlight->shadowmode)
3753 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3754 if (model->CompileShadowMap && rtlight->shadow)
3755 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3758 if (model->CompileShadowVolume && rtlight->shadow)
3759 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3762 R_FrameData_ReturnToMark();
3763 // now we're done compiling the rtlight
3764 r_shadow_compilingrtlight = NULL;
3768 // use smallest available cullradius - box radius or light radius
3769 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3770 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3772 shadowzpasstris = 0;
3773 if (rtlight->static_meshchain_shadow_zpass)
3774 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3775 shadowzpasstris += mesh->numtriangles;
3777 shadowzfailtris = 0;
3778 if (rtlight->static_meshchain_shadow_zfail)
3779 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3780 shadowzfailtris += mesh->numtriangles;
3783 if (rtlight->static_numlighttrispvsbytes)
3784 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3785 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3789 if (rtlight->static_numshadowtrispvsbytes)
3790 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3791 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3794 if (developer_extra.integer)
3795 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);
3798 void R_RTLight_Uncompile(rtlight_t *rtlight)
3800 if (rtlight->compiled)
3802 if (rtlight->static_meshchain_shadow_zpass)
3803 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3804 rtlight->static_meshchain_shadow_zpass = NULL;
3805 if (rtlight->static_meshchain_shadow_zfail)
3806 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3807 rtlight->static_meshchain_shadow_zfail = NULL;
3808 if (rtlight->static_meshchain_shadow_shadowmap)
3809 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3810 rtlight->static_meshchain_shadow_shadowmap = NULL;
3811 // these allocations are grouped
3812 if (rtlight->static_surfacelist)
3813 Mem_Free(rtlight->static_surfacelist);
3814 rtlight->static_numleafs = 0;
3815 rtlight->static_numleafpvsbytes = 0;
3816 rtlight->static_leaflist = NULL;
3817 rtlight->static_leafpvs = NULL;
3818 rtlight->static_numsurfaces = 0;
3819 rtlight->static_surfacelist = NULL;
3820 rtlight->static_numshadowtrispvsbytes = 0;
3821 rtlight->static_shadowtrispvs = NULL;
3822 rtlight->static_numlighttrispvsbytes = 0;
3823 rtlight->static_lighttrispvs = NULL;
3824 rtlight->compiled = false;
3828 void R_Shadow_UncompileWorldLights(void)
3832 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3833 for (lightindex = 0;lightindex < range;lightindex++)
3835 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3838 R_RTLight_Uncompile(&light->rtlight);
3842 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3846 // reset the count of frustum planes
3847 // see rtlight->cached_frustumplanes definition for how much this array
3849 rtlight->cached_numfrustumplanes = 0;
3851 if (r_trippy.integer)
3854 // haven't implemented a culling path for ortho rendering
3855 if (!r_refdef.view.useperspective)
3857 // check if the light is on screen and copy the 4 planes if it is
3858 for (i = 0;i < 4;i++)
3859 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3862 for (i = 0;i < 4;i++)
3863 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3868 // generate a deformed frustum that includes the light origin, this is
3869 // used to cull shadow casting surfaces that can not possibly cast a
3870 // shadow onto the visible light-receiving surfaces, which can be a
3873 // if the light origin is onscreen the result will be 4 planes exactly
3874 // if the light origin is offscreen on only one axis the result will
3875 // be exactly 5 planes (split-side case)
3876 // if the light origin is offscreen on two axes the result will be
3877 // exactly 4 planes (stretched corner case)
3878 for (i = 0;i < 4;i++)
3880 // quickly reject standard frustum planes that put the light
3881 // origin outside the frustum
3882 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3885 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3887 // if all the standard frustum planes were accepted, the light is onscreen
3888 // otherwise we need to generate some more planes below...
3889 if (rtlight->cached_numfrustumplanes < 4)
3891 // at least one of the stock frustum planes failed, so we need to
3892 // create one or two custom planes to enclose the light origin
3893 for (i = 0;i < 4;i++)
3895 // create a plane using the view origin and light origin, and a
3896 // single point from the frustum corner set
3897 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3898 VectorNormalize(plane.normal);
3899 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3900 // see if this plane is backwards and flip it if so
3901 for (j = 0;j < 4;j++)
3902 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3906 VectorNegate(plane.normal, plane.normal);
3908 // flipped plane, test again to see if it is now valid
3909 for (j = 0;j < 4;j++)
3910 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3912 // if the plane is still not valid, then it is dividing the
3913 // frustum and has to be rejected
3917 // we have created a valid plane, compute extra info
3918 PlaneClassify(&plane);
3920 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3922 // if we've found 5 frustum planes then we have constructed a
3923 // proper split-side case and do not need to keep searching for
3924 // planes to enclose the light origin
3925 if (rtlight->cached_numfrustumplanes == 5)
3933 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3935 plane = rtlight->cached_frustumplanes[i];
3936 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));
3941 // now add the light-space box planes if the light box is rotated, as any
3942 // caster outside the oriented light box is irrelevant (even if it passed
3943 // the worldspace light box, which is axial)
3944 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3946 for (i = 0;i < 6;i++)
3950 v[i >> 1] = (i & 1) ? -1 : 1;
3951 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3952 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3953 plane.dist = VectorNormalizeLength(plane.normal);
3954 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3955 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3961 // add the world-space reduced box planes
3962 for (i = 0;i < 6;i++)
3964 VectorClear(plane.normal);
3965 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3966 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3967 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3976 // reduce all plane distances to tightly fit the rtlight cull box, which
3978 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3979 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3980 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3981 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3982 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3983 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3984 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3985 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3986 oldnum = rtlight->cached_numfrustumplanes;
3987 rtlight->cached_numfrustumplanes = 0;
3988 for (j = 0;j < oldnum;j++)
3990 // find the nearest point on the box to this plane
3991 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3992 for (i = 1;i < 8;i++)
3994 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3995 if (bestdist > dist)
3998 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);
3999 // if the nearest point is near or behind the plane, we want this
4000 // plane, otherwise the plane is useless as it won't cull anything
4001 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
4003 PlaneClassify(&rtlight->cached_frustumplanes[j]);
4004 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
4011 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
4015 RSurf_ActiveWorldEntity();
4017 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4020 GL_CullFace(GL_NONE);
4021 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
4022 for (;mesh;mesh = mesh->next)
4024 if (!mesh->sidetotals[r_shadow_shadowmapside])
4026 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
4027 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4028 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
4032 else if (r_refdef.scene.worldentity->model)
4033 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);
4035 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4038 static void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
4040 qboolean zpass = false;
4043 int surfacelistindex;
4044 msurface_t *surface;
4046 // if triangle neighbors are disabled, shadowvolumes are disabled
4047 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
4050 RSurf_ActiveWorldEntity();
4052 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4055 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
4057 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
4058 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
4060 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
4061 for (;mesh;mesh = mesh->next)
4063 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->numtriangles;
4064 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4065 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
4067 // increment stencil if frontface is infront of depthbuffer
4068 GL_CullFace(r_refdef.view.cullface_back);
4069 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
4070 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
4071 // decrement stencil if backface is infront of depthbuffer
4072 GL_CullFace(r_refdef.view.cullface_front);
4073 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
4075 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
4077 // decrement stencil if backface is behind depthbuffer
4078 GL_CullFace(r_refdef.view.cullface_front);
4079 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
4080 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
4081 // increment stencil if frontface is behind depthbuffer
4082 GL_CullFace(r_refdef.view.cullface_back);
4083 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
4085 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
4089 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
4091 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
4092 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
4093 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
4095 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
4096 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
4097 if (CHECKPVSBIT(trispvs, t))
4098 shadowmarklist[numshadowmark++] = t;
4100 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);
4102 else if (numsurfaces)
4104 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);
4107 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4110 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
4112 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
4113 vec_t relativeshadowradius;
4114 RSurf_ActiveModelEntity(ent, false, false, false);
4115 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
4116 // we need to re-init the shader for each entity because the matrix changed
4117 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
4118 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
4119 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
4120 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
4121 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
4122 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
4123 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
4124 switch (r_shadow_rendermode)
4126 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
4127 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4130 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4133 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4136 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
4138 // set up properties for rendering light onto this entity
4139 RSurf_ActiveModelEntity(ent, true, true, false);
4140 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
4141 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4142 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4143 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4146 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
4148 if (!r_refdef.scene.worldmodel->DrawLight)
4151 // set up properties for rendering light onto this entity
4152 RSurf_ActiveWorldEntity();
4153 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
4154 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4155 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4156 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4158 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
4160 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4163 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
4165 dp_model_t *model = ent->model;
4166 if (!model->DrawLight)
4169 R_Shadow_SetupEntityLight(ent);
4171 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
4173 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4176 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
4180 int numleafs, numsurfaces;
4181 int *leaflist, *surfacelist;
4182 unsigned char *leafpvs;
4183 unsigned char *shadowtrispvs;
4184 unsigned char *lighttrispvs;
4185 //unsigned char *surfacesides;
4186 int numlightentities;
4187 int numlightentities_noselfshadow;
4188 int numshadowentities;
4189 int numshadowentities_noselfshadow;
4190 static entity_render_t *lightentities[MAX_EDICTS];
4191 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
4192 static entity_render_t *shadowentities[MAX_EDICTS];
4193 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
4195 qboolean castshadows;
4197 rtlight->draw = false;
4198 rtlight->cached_numlightentities = 0;
4199 rtlight->cached_numlightentities_noselfshadow = 0;
4200 rtlight->cached_numshadowentities = 0;
4201 rtlight->cached_numshadowentities_noselfshadow = 0;
4202 rtlight->cached_numsurfaces = 0;
4203 rtlight->cached_lightentities = NULL;
4204 rtlight->cached_lightentities_noselfshadow = NULL;
4205 rtlight->cached_shadowentities = NULL;
4206 rtlight->cached_shadowentities_noselfshadow = NULL;
4207 rtlight->cached_shadowtrispvs = NULL;
4208 rtlight->cached_lighttrispvs = NULL;
4209 rtlight->cached_surfacelist = NULL;
4211 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
4212 // skip lights that are basically invisible (color 0 0 0)
4213 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
4215 // loading is done before visibility checks because loading should happen
4216 // all at once at the start of a level, not when it stalls gameplay.
4217 // (especially important to benchmarks)
4219 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
4221 if (rtlight->compiled)
4222 R_RTLight_Uncompile(rtlight);
4223 R_RTLight_Compile(rtlight);
4227 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
4229 // look up the light style value at this time
4230 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4231 VectorScale(rtlight->color, f, rtlight->currentcolor);
4233 if (rtlight->selected)
4235 f = 2 + sin(realtime * M_PI * 4.0);
4236 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
4240 // if lightstyle is currently off, don't draw the light
4241 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
4244 // skip processing on corona-only lights
4248 // if the light box is offscreen, skip it
4249 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
4252 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
4253 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
4255 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4257 // don't allow lights to be drawn if using r_shadow_bouncegrid 2, except if we're using static bouncegrid where dynamic lights still need to draw
4258 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
4261 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
4263 // compiled light, world available and can receive realtime lighting
4264 // retrieve leaf information
4265 numleafs = rtlight->static_numleafs;
4266 leaflist = rtlight->static_leaflist;
4267 leafpvs = rtlight->static_leafpvs;
4268 numsurfaces = rtlight->static_numsurfaces;
4269 surfacelist = rtlight->static_surfacelist;
4270 //surfacesides = NULL;
4271 shadowtrispvs = rtlight->static_shadowtrispvs;
4272 lighttrispvs = rtlight->static_lighttrispvs;
4274 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4276 // dynamic light, world available and can receive realtime lighting
4277 // calculate lit surfaces and leafs
4278 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);
4279 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4280 leaflist = r_shadow_buffer_leaflist;
4281 leafpvs = r_shadow_buffer_leafpvs;
4282 surfacelist = r_shadow_buffer_surfacelist;
4283 //surfacesides = r_shadow_buffer_surfacesides;
4284 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4285 lighttrispvs = r_shadow_buffer_lighttrispvs;
4286 // if the reduced leaf bounds are offscreen, skip it
4287 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4298 //surfacesides = NULL;
4299 shadowtrispvs = NULL;
4300 lighttrispvs = NULL;
4302 // check if light is illuminating any visible leafs
4305 for (i = 0;i < numleafs;i++)
4306 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4312 // make a list of lit entities and shadow casting entities
4313 numlightentities = 0;
4314 numlightentities_noselfshadow = 0;
4315 numshadowentities = 0;
4316 numshadowentities_noselfshadow = 0;
4318 // add dynamic entities that are lit by the light
4319 for (i = 0;i < r_refdef.scene.numentities;i++)
4322 entity_render_t *ent = r_refdef.scene.entities[i];
4324 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4326 // skip the object entirely if it is not within the valid
4327 // shadow-casting region (which includes the lit region)
4328 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
4330 if (!(model = ent->model))
4332 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4334 // this entity wants to receive light, is visible, and is
4335 // inside the light box
4336 // TODO: check if the surfaces in the model can receive light
4337 // so now check if it's in a leaf seen by the light
4338 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))
4340 if (ent->flags & RENDER_NOSELFSHADOW)
4341 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
4343 lightentities[numlightentities++] = ent;
4344 // since it is lit, it probably also casts a shadow...
4345 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4346 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4347 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4349 // note: exterior models without the RENDER_NOSELFSHADOW
4350 // flag still create a RENDER_NOSELFSHADOW shadow but
4351 // are lit normally, this means that they are
4352 // self-shadowing but do not shadow other
4353 // RENDER_NOSELFSHADOW entities such as the gun
4354 // (very weird, but keeps the player shadow off the gun)
4355 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4356 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4358 shadowentities[numshadowentities++] = ent;
4361 else if (ent->flags & RENDER_SHADOW)
4363 // this entity is not receiving light, but may still need to
4365 // TODO: check if the surfaces in the model can cast shadow
4366 // now check if it is in a leaf seen by the light
4367 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))
4369 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4370 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4371 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4373 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4374 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4376 shadowentities[numshadowentities++] = ent;
4381 // return if there's nothing at all to light
4382 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4385 // count this light in the r_speeds
4386 r_refdef.stats[r_stat_lights]++;
4388 // flag it as worth drawing later
4389 rtlight->draw = true;
4391 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
4392 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4394 numshadowentities = numshadowentities_noselfshadow = 0;
4396 // cache all the animated entities that cast a shadow but are not visible
4397 for (i = 0;i < numshadowentities;i++)
4398 R_AnimCache_GetEntity(shadowentities[i], false, false);
4399 for (i = 0;i < numshadowentities_noselfshadow;i++)
4400 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4402 // allocate some temporary memory for rendering this light later in the frame
4403 // reusable buffers need to be copied, static data can be used as-is
4404 rtlight->cached_numlightentities = numlightentities;
4405 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
4406 rtlight->cached_numshadowentities = numshadowentities;
4407 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4408 rtlight->cached_numsurfaces = numsurfaces;
4409 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4410 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4411 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4412 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4413 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4415 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4416 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4417 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4418 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4419 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4423 // compiled light data
4424 rtlight->cached_shadowtrispvs = shadowtrispvs;
4425 rtlight->cached_lighttrispvs = lighttrispvs;
4426 rtlight->cached_surfacelist = surfacelist;
4430 static void R_Shadow_DrawLight(rtlight_t *rtlight)
4434 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4435 int numlightentities;
4436 int numlightentities_noselfshadow;
4437 int numshadowentities;
4438 int numshadowentities_noselfshadow;
4439 entity_render_t **lightentities;
4440 entity_render_t **lightentities_noselfshadow;
4441 entity_render_t **shadowentities;
4442 entity_render_t **shadowentities_noselfshadow;
4444 static unsigned char entitysides[MAX_EDICTS];
4445 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4446 vec3_t nearestpoint;
4448 qboolean castshadows;
4451 // check if we cached this light this frame (meaning it is worth drawing)
4455 numlightentities = rtlight->cached_numlightentities;
4456 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4457 numshadowentities = rtlight->cached_numshadowentities;
4458 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4459 numsurfaces = rtlight->cached_numsurfaces;
4460 lightentities = rtlight->cached_lightentities;
4461 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4462 shadowentities = rtlight->cached_shadowentities;
4463 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4464 shadowtrispvs = rtlight->cached_shadowtrispvs;
4465 lighttrispvs = rtlight->cached_lighttrispvs;
4466 surfacelist = rtlight->cached_surfacelist;
4468 // set up a scissor rectangle for this light
4469 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4472 // don't let sound skip if going slow
4473 if (r_refdef.scene.extraupdate)
4476 // make this the active rtlight for rendering purposes
4477 R_Shadow_RenderMode_ActiveLight(rtlight);
4479 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4481 // optionally draw visible shape of the shadow volumes
4482 // for performance analysis by level designers
4483 R_Shadow_RenderMode_VisibleShadowVolumes();
4485 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4486 for (i = 0;i < numshadowentities;i++)
4487 R_Shadow_DrawEntityShadow(shadowentities[i]);
4488 for (i = 0;i < numshadowentities_noselfshadow;i++)
4489 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4490 R_Shadow_RenderMode_VisibleLighting(false, false);
4493 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4495 // optionally draw the illuminated areas
4496 // for performance analysis by level designers
4497 R_Shadow_RenderMode_VisibleLighting(false, false);
4499 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4500 for (i = 0;i < numlightentities;i++)
4501 R_Shadow_DrawEntityLight(lightentities[i]);
4502 for (i = 0;i < numlightentities_noselfshadow;i++)
4503 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4506 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4508 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4509 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4510 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4511 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4513 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
4514 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4515 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4517 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4523 int receivermask = 0;
4524 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4525 Matrix4x4_Abs(&radiustolight);
4527 r_shadow_shadowmaplod = 0;
4528 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4529 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
4530 r_shadow_shadowmaplod = i;
4532 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4534 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4536 surfacesides = NULL;
4539 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4541 castermask = rtlight->static_shadowmap_casters;
4542 receivermask = rtlight->static_shadowmap_receivers;
4546 surfacesides = r_shadow_buffer_surfacesides;
4547 for(i = 0;i < numsurfaces;i++)
4549 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4550 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4551 castermask |= surfacesides[i];
4552 receivermask |= surfacesides[i];
4556 if (receivermask < 0x3F)
4558 for (i = 0;i < numlightentities;i++)
4559 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4560 if (receivermask < 0x3F)
4561 for(i = 0; i < numlightentities_noselfshadow;i++)
4562 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4565 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4569 for (i = 0;i < numshadowentities;i++)
4570 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4571 for (i = 0;i < numshadowentities_noselfshadow;i++)
4572 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4575 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4577 // render shadow casters into 6 sided depth texture
4578 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4580 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
4581 if (! (castermask & (1 << side))) continue;
4583 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4584 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4585 R_Shadow_DrawEntityShadow(shadowentities[i]);
4588 if (numlightentities_noselfshadow)
4590 // render lighting using the depth texture as shadowmap
4591 // draw lighting in the unmasked areas
4592 R_Shadow_RenderMode_Lighting(false, false, true);
4593 for (i = 0;i < numlightentities_noselfshadow;i++)
4594 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4597 // render shadow casters into 6 sided depth texture
4598 if (numshadowentities_noselfshadow)
4600 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4602 R_Shadow_RenderMode_ShadowMap(side, 0, size);
4603 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
4604 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4608 // render lighting using the depth texture as shadowmap
4609 // draw lighting in the unmasked areas
4610 R_Shadow_RenderMode_Lighting(false, false, true);
4611 // draw lighting in the unmasked areas
4613 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4614 for (i = 0;i < numlightentities;i++)
4615 R_Shadow_DrawEntityLight(lightentities[i]);
4617 else if (castshadows && vid.stencil)
4619 // draw stencil shadow volumes to mask off pixels that are in shadow
4620 // so that they won't receive lighting
4621 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4622 R_Shadow_ClearStencil();
4625 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4626 for (i = 0;i < numshadowentities;i++)
4627 R_Shadow_DrawEntityShadow(shadowentities[i]);
4629 // draw lighting in the unmasked areas
4630 R_Shadow_RenderMode_Lighting(true, false, false);
4631 for (i = 0;i < numlightentities_noselfshadow;i++)
4632 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4634 for (i = 0;i < numshadowentities_noselfshadow;i++)
4635 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4637 // draw lighting in the unmasked areas
4638 R_Shadow_RenderMode_Lighting(true, false, false);
4640 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4641 for (i = 0;i < numlightentities;i++)
4642 R_Shadow_DrawEntityLight(lightentities[i]);
4646 // draw lighting in the unmasked areas
4647 R_Shadow_RenderMode_Lighting(false, false, false);
4649 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4650 for (i = 0;i < numlightentities;i++)
4651 R_Shadow_DrawEntityLight(lightentities[i]);
4652 for (i = 0;i < numlightentities_noselfshadow;i++)
4653 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4656 if (r_shadow_usingdeferredprepass)
4658 // when rendering deferred lighting, we simply rasterize the box
4659 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4660 R_Shadow_RenderMode_DrawDeferredLight(false, true);
4661 else if (castshadows && vid.stencil)
4662 R_Shadow_RenderMode_DrawDeferredLight(true, false);
4664 R_Shadow_RenderMode_DrawDeferredLight(false, false);
4668 static void R_Shadow_FreeDeferred(void)
4670 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
4671 r_shadow_prepassgeometryfbo = 0;
4673 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
4674 r_shadow_prepasslightingdiffusespecularfbo = 0;
4676 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
4677 r_shadow_prepasslightingdiffusefbo = 0;
4679 if (r_shadow_prepassgeometrydepthbuffer)
4680 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
4681 r_shadow_prepassgeometrydepthbuffer = NULL;
4683 if (r_shadow_prepassgeometrynormalmaptexture)
4684 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4685 r_shadow_prepassgeometrynormalmaptexture = NULL;
4687 if (r_shadow_prepasslightingdiffusetexture)
4688 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
4689 r_shadow_prepasslightingdiffusetexture = NULL;
4691 if (r_shadow_prepasslightingspeculartexture)
4692 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4693 r_shadow_prepasslightingspeculartexture = NULL;
4696 void R_Shadow_DrawPrepass(void)
4704 entity_render_t *ent;
4705 float clearcolor[4];
4707 R_Mesh_ResetTextureState();
4709 GL_ColorMask(1,1,1,1);
4710 GL_BlendFunc(GL_ONE, GL_ZERO);
4713 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4714 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4715 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4716 if (r_timereport_active)
4717 R_TimeReport("prepasscleargeom");
4719 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4720 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4721 if (r_timereport_active)
4722 R_TimeReport("prepassworld");
4724 for (i = 0;i < r_refdef.scene.numentities;i++)
4726 if (!r_refdef.viewcache.entityvisible[i])
4728 ent = r_refdef.scene.entities[i];
4729 if (ent->model && ent->model->DrawPrepass != NULL)
4730 ent->model->DrawPrepass(ent);
4733 if (r_timereport_active)
4734 R_TimeReport("prepassmodels");
4736 GL_DepthMask(false);
4737 GL_ColorMask(1,1,1,1);
4740 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4741 Vector4Set(clearcolor, 0, 0, 0, 0);
4742 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4743 if (r_timereport_active)
4744 R_TimeReport("prepassclearlit");
4746 R_Shadow_RenderMode_Begin();
4748 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4749 if (r_shadow_debuglight.integer >= 0)
4751 lightindex = r_shadow_debuglight.integer;
4752 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4753 if (light && (light->flags & flag) && light->rtlight.draw)
4754 R_Shadow_DrawLight(&light->rtlight);
4758 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4759 for (lightindex = 0;lightindex < range;lightindex++)
4761 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4762 if (light && (light->flags & flag) && light->rtlight.draw)
4763 R_Shadow_DrawLight(&light->rtlight);
4766 if (r_refdef.scene.rtdlight)
4767 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4768 if (r_refdef.scene.lights[lnum]->draw)
4769 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4771 R_Shadow_RenderMode_End();
4773 if (r_timereport_active)
4774 R_TimeReport("prepasslights");
4777 void R_Shadow_DrawLightSprites(void);
4778 void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
4787 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4788 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4789 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
4790 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4791 r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) ||
4792 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4793 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16) ||
4794 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
4795 R_Shadow_FreeShadowMaps();
4797 r_shadow_fb_fbo = fbo;
4798 r_shadow_fb_depthtexture = depthtexture;
4799 r_shadow_fb_colortexture = colortexture;
4801 r_shadow_usingshadowmaportho = false;
4803 switch (vid.renderpath)
4805 case RENDERPATH_GL20:
4806 case RENDERPATH_D3D9:
4807 case RENDERPATH_D3D10:
4808 case RENDERPATH_D3D11:
4809 case RENDERPATH_SOFT:
4811 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4813 r_shadow_usingdeferredprepass = false;
4814 if (r_shadow_prepass_width)
4815 R_Shadow_FreeDeferred();
4816 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4820 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4822 R_Shadow_FreeDeferred();
4824 r_shadow_usingdeferredprepass = true;
4825 r_shadow_prepass_width = vid.width;
4826 r_shadow_prepass_height = vid.height;
4827 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
4828 r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER32F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4829 r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER16F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4830 r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER16F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4832 // set up the geometry pass fbo (depth + normalmap)
4833 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4834 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4835 // render depth into a renderbuffer and other important properties into the normalmap texture
4837 // set up the lighting pass fbo (diffuse + specular)
4838 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4839 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4840 // render diffuse into one texture and specular into another,
4841 // with depth and normalmap bound as textures,
4842 // with depth bound as attachment as well
4844 // set up the lighting pass fbo (diffuse)
4845 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4846 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4847 // render diffuse into one texture,
4848 // with depth and normalmap bound as textures,
4849 // with depth bound as attachment as well
4853 case RENDERPATH_GL11:
4854 case RENDERPATH_GL13:
4855 case RENDERPATH_GLES1:
4856 case RENDERPATH_GLES2:
4857 r_shadow_usingdeferredprepass = false;
4861 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);
4863 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4864 if (r_shadow_debuglight.integer >= 0)
4866 lightindex = r_shadow_debuglight.integer;
4867 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4869 R_Shadow_PrepareLight(&light->rtlight);
4873 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4874 for (lightindex = 0;lightindex < range;lightindex++)
4876 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4877 if (light && (light->flags & flag))
4878 R_Shadow_PrepareLight(&light->rtlight);
4881 if (r_refdef.scene.rtdlight)
4883 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4884 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4886 else if(gl_flashblend.integer)
4888 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4890 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4891 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4892 VectorScale(rtlight->color, f, rtlight->currentcolor);
4896 if (r_editlights.integer)
4897 R_Shadow_DrawLightSprites();
4900 void R_Shadow_DrawLights(void)
4908 R_Shadow_RenderMode_Begin();
4910 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4911 if (r_shadow_debuglight.integer >= 0)
4913 lightindex = r_shadow_debuglight.integer;
4914 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4916 R_Shadow_DrawLight(&light->rtlight);
4920 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4921 for (lightindex = 0;lightindex < range;lightindex++)
4923 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4924 if (light && (light->flags & flag))
4925 R_Shadow_DrawLight(&light->rtlight);
4928 if (r_refdef.scene.rtdlight)
4929 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4930 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4932 R_Shadow_RenderMode_End();
4935 #define MAX_MODELSHADOWS 1024
4936 static int r_shadow_nummodelshadows;
4937 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
4939 void R_Shadow_PrepareModelShadows(void)
4942 float scale, size, radius, dot1, dot2;
4943 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4944 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4945 entity_render_t *ent;
4947 r_shadow_nummodelshadows = 0;
4948 if (!r_refdef.scene.numentities)
4951 switch (r_shadow_shadowmode)
4953 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4954 if (r_shadows.integer >= 2)
4957 case R_SHADOW_SHADOWMODE_STENCIL:
4960 for (i = 0;i < r_refdef.scene.numentities;i++)
4962 ent = r_refdef.scene.entities[i];
4963 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4965 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
4967 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
4968 R_AnimCache_GetEntity(ent, false, false);
4976 size = 2*r_shadow_shadowmapmaxsize;
4977 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4978 radius = 0.5f * size / scale;
4980 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4981 VectorCopy(prvmshadowdir, shadowdir);
4982 VectorNormalize(shadowdir);
4983 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4984 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4985 if (fabs(dot1) <= fabs(dot2))
4986 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4988 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4989 VectorNormalize(shadowforward);
4990 CrossProduct(shadowdir, shadowforward, shadowright);
4991 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4992 VectorCopy(prvmshadowfocus, shadowfocus);
4993 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4994 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4995 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4996 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4997 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4999 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5001 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5002 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5003 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5004 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5005 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5006 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5008 for (i = 0;i < r_refdef.scene.numentities;i++)
5010 ent = r_refdef.scene.entities[i];
5011 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
5013 // cast shadows from anything of the map (submodels are optional)
5014 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5016 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5018 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5019 R_AnimCache_GetEntity(ent, false, false);
5024 void R_DrawModelShadowMaps(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
5027 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
5028 entity_render_t *ent;
5029 vec3_t relativelightorigin;
5030 vec3_t relativelightdirection, relativeforward, relativeright;
5031 vec3_t relativeshadowmins, relativeshadowmaxs;
5032 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
5033 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5035 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
5036 r_viewport_t viewport;
5037 GLuint shadowfbo = 0;
5038 float clearcolor[4];
5040 if (!r_shadow_nummodelshadows)
5043 switch (r_shadow_shadowmode)
5045 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
5051 r_shadow_fb_fbo = fbo;
5052 r_shadow_fb_depthtexture = depthtexture;
5053 r_shadow_fb_colortexture = colortexture;
5055 R_ResetViewRendering3D(fbo, depthtexture, colortexture);
5056 R_Shadow_RenderMode_Begin();
5057 R_Shadow_RenderMode_ActiveLight(NULL);
5059 switch (r_shadow_shadowmode)
5061 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
5062 if (!r_shadow_shadowmap2ddepthtexture)
5063 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
5064 shadowfbo = r_shadow_fbo2d;
5065 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
5066 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
5067 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
5073 size = 2*r_shadow_shadowmapmaxsize;
5074 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
5075 radius = 0.5f / scale;
5076 nearclip = -r_shadows_throwdistance.value;
5077 farclip = r_shadows_throwdistance.value;
5078 bias = (r_shadows_shadowmapbias.value < 0) ? r_shadow_shadowmapping_bias.value : r_shadows_shadowmapbias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
5080 r_shadow_shadowmap_parameters[0] = size;
5081 r_shadow_shadowmap_parameters[1] = size;
5082 r_shadow_shadowmap_parameters[2] = 1.0;
5083 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
5085 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5086 VectorCopy(prvmshadowdir, shadowdir);
5087 VectorNormalize(shadowdir);
5088 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5089 VectorCopy(prvmshadowfocus, shadowfocus);
5090 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5091 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5092 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5093 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5094 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5095 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5096 if (fabs(dot1) <= fabs(dot2))
5097 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5099 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5100 VectorNormalize(shadowforward);
5101 VectorM(scale, shadowforward, &m[0]);
5102 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5104 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
5105 CrossProduct(shadowdir, shadowforward, shadowright);
5106 VectorM(scale, shadowright, &m[4]);
5107 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
5108 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
5109 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
5110 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
5111 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
5112 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
5114 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5116 if (r_shadow_shadowmap2ddepthbuffer)
5117 R_Mesh_SetRenderTargets(shadowfbo, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
5119 R_Mesh_SetRenderTargets(shadowfbo, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
5120 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
5121 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
5124 R_SetViewport(&viewport);
5125 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
5126 Vector4Set(clearcolor, 1,1,1,1);
5127 // in D3D9 we have to render to a color texture shadowmap
5128 // in GL we render directly to a depth texture only
5129 if (r_shadow_shadowmap2ddepthbuffer)
5130 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
5132 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
5133 // render into a slightly restricted region so that the borders of the
5134 // shadowmap area fade away, rather than streaking across everything
5135 // outside the usable area
5136 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
5138 for (i = 0;i < r_shadow_nummodelshadows;i++)
5140 ent = r_shadow_modelshadows[i];
5141 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5142 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
5143 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5144 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
5145 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
5146 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5147 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5148 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5149 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5150 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5151 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5152 RSurf_ActiveModelEntity(ent, false, false, false);
5153 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
5154 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5160 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
5162 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
5164 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
5165 Cvar_SetValueQuick(&r_test, 0);
5170 R_Shadow_RenderMode_End();
5172 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
5173 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
5174 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
5175 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
5176 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
5177 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
5179 switch (vid.renderpath)
5181 case RENDERPATH_GL11:
5182 case RENDERPATH_GL13:
5183 case RENDERPATH_GL20:
5184 case RENDERPATH_SOFT:
5185 case RENDERPATH_GLES1:
5186 case RENDERPATH_GLES2:
5188 case RENDERPATH_D3D9:
5189 case RENDERPATH_D3D10:
5190 case RENDERPATH_D3D11:
5191 #ifdef MATRIX4x4_OPENGLORIENTATION
5192 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5193 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
5194 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
5195 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
5197 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5198 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
5199 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
5200 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
5205 r_shadow_usingshadowmaportho = true;
5206 switch (r_shadow_shadowmode)
5208 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
5209 r_shadow_usingshadowmap2d = true;
5216 void R_DrawModelShadows(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
5219 float relativethrowdistance;
5220 entity_render_t *ent;
5221 vec3_t relativelightorigin;
5222 vec3_t relativelightdirection;
5223 vec3_t relativeshadowmins, relativeshadowmaxs;
5224 vec3_t tmp, shadowdir;
5225 prvm_vec3_t prvmshadowdir;
5227 if (!r_shadow_nummodelshadows || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
5230 r_shadow_fb_fbo = fbo;
5231 r_shadow_fb_depthtexture = depthtexture;
5232 r_shadow_fb_colortexture = colortexture;
5234 R_ResetViewRendering3D(fbo, depthtexture, colortexture);
5235 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
5236 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5237 R_Shadow_RenderMode_Begin();
5238 R_Shadow_RenderMode_ActiveLight(NULL);
5239 r_shadow_lightscissor[0] = r_refdef.view.x;
5240 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
5241 r_shadow_lightscissor[2] = r_refdef.view.width;
5242 r_shadow_lightscissor[3] = r_refdef.view.height;
5243 R_Shadow_RenderMode_StencilShadowVolumes(false);
5246 if (r_shadows.integer == 2)
5248 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5249 VectorCopy(prvmshadowdir, shadowdir);
5250 VectorNormalize(shadowdir);
5253 R_Shadow_ClearStencil();
5255 for (i = 0;i < r_shadow_nummodelshadows;i++)
5257 ent = r_shadow_modelshadows[i];
5259 // cast shadows from anything of the map (submodels are optional)
5260 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5261 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
5262 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
5263 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
5264 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5267 if(ent->entitynumber != 0)
5269 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
5271 // FIXME handle this
5272 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5276 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
5277 int entnum, entnum2, recursion;
5278 entnum = entnum2 = ent->entitynumber;
5279 for(recursion = 32; recursion > 0; --recursion)
5281 entnum2 = cl.entities[entnum].state_current.tagentity;
5282 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
5287 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
5289 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
5290 // transform into modelspace of OUR entity
5291 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
5292 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
5295 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5299 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5302 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
5303 RSurf_ActiveModelEntity(ent, false, false, false);
5304 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
5305 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5308 // not really the right mode, but this will disable any silly stencil features
5309 R_Shadow_RenderMode_End();
5311 // set up ortho view for rendering this pass
5312 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5313 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5314 //GL_ScissorTest(true);
5315 //R_EntityMatrix(&identitymatrix);
5316 //R_Mesh_ResetTextureState();
5317 R_ResetViewRendering2D(fbo, depthtexture, colortexture);
5319 // set up a darkening blend on shadowed areas
5320 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5321 //GL_DepthRange(0, 1);
5322 //GL_DepthTest(false);
5323 //GL_DepthMask(false);
5324 //GL_PolygonOffset(0, 0);CHECKGLERROR
5325 GL_Color(0, 0, 0, r_shadows_darken.value);
5326 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5327 //GL_DepthFunc(GL_ALWAYS);
5328 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5330 // apply the blend to the shadowed areas
5331 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5332 R_SetupShader_Generic_NoTexture(false, true);
5333 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5335 // restore the viewport
5336 R_SetViewport(&r_refdef.view.viewport);
5338 // restore other state to normal
5339 //R_Shadow_RenderMode_End();
5342 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5345 vec3_t centerorigin;
5346 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5349 // if it's too close, skip it
5350 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5352 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5355 if (usequery && r_numqueries + 2 <= r_maxqueries)
5357 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5358 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5359 // 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
5360 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5362 switch(vid.renderpath)
5364 case RENDERPATH_GL11:
5365 case RENDERPATH_GL13:
5366 case RENDERPATH_GL20:
5367 case RENDERPATH_GLES1:
5368 case RENDERPATH_GLES2:
5369 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5371 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5372 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5373 GL_DepthFunc(GL_ALWAYS);
5374 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5375 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5376 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5377 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5378 GL_DepthFunc(GL_LEQUAL);
5379 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5380 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5381 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5382 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5383 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5387 case RENDERPATH_D3D9:
5388 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5390 case RENDERPATH_D3D10:
5391 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5393 case RENDERPATH_D3D11:
5394 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5396 case RENDERPATH_SOFT:
5397 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5401 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5404 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5406 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5409 unsigned int occlude = 0;
5410 GLint allpixels = 0, visiblepixels = 0;
5412 // now we have to check the query result
5413 if (rtlight->corona_queryindex_visiblepixels)
5415 switch(vid.renderpath)
5417 case RENDERPATH_GL11:
5418 case RENDERPATH_GL13:
5419 case RENDERPATH_GL20:
5420 case RENDERPATH_GLES1:
5421 case RENDERPATH_GLES2:
5422 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5424 // See if we can use the GPU-side method to prevent implicit sync
5425 if (vid.support.arb_query_buffer_object) {
5426 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
5427 if (!r_shadow_occlusion_buf) {
5428 qglGenBuffersARB(1, &r_shadow_occlusion_buf);
5429 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5430 qglBufferDataARB(GL_QUERY_BUFFER_ARB, 8, NULL, GL_DYNAMIC_COPY);
5432 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5434 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(0));
5435 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4));
5436 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
5437 occlude = MATERIALFLAG_OCCLUDE;
5439 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5440 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5441 if (visiblepixels < 1 || allpixels < 1)
5443 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5445 cscale *= rtlight->corona_visibility;
5451 case RENDERPATH_D3D9:
5452 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5454 case RENDERPATH_D3D10:
5455 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5457 case RENDERPATH_D3D11:
5458 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5460 case RENDERPATH_SOFT:
5461 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5469 // FIXME: these traces should scan all render entities instead of cl.world
5470 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
5473 VectorScale(rtlight->currentcolor, cscale, color);
5474 if (VectorLength(color) > (1.0f / 256.0f))
5477 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
5480 VectorNegate(color, color);
5481 GL_BlendEquationSubtract(true);
5483 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5484 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);
5485 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
5487 GL_BlendEquationSubtract(false);
5491 void R_Shadow_DrawCoronas(void)
5494 qboolean usequery = false;
5499 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
5501 if (r_fb.water.renderingscene)
5503 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5504 R_EntityMatrix(&identitymatrix);
5506 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5508 // check occlusion of coronas
5509 // use GL_ARB_occlusion_query if available
5510 // otherwise use raytraces
5512 switch (vid.renderpath)
5514 case RENDERPATH_GL11:
5515 case RENDERPATH_GL13:
5516 case RENDERPATH_GL20:
5517 case RENDERPATH_GLES1:
5518 case RENDERPATH_GLES2:
5519 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
5520 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5523 GL_ColorMask(0,0,0,0);
5524 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
5525 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
5528 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
5529 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
5531 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
5534 RSurf_ActiveWorldEntity();
5535 GL_BlendFunc(GL_ONE, GL_ZERO);
5536 GL_CullFace(GL_NONE);
5537 GL_DepthMask(false);
5538 GL_DepthRange(0, 1);
5539 GL_PolygonOffset(0, 0);
5541 R_Mesh_ResetTextureState();
5542 R_SetupShader_Generic_NoTexture(false, false);
5546 case RENDERPATH_D3D9:
5548 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5550 case RENDERPATH_D3D10:
5551 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5553 case RENDERPATH_D3D11:
5554 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5556 case RENDERPATH_SOFT:
5558 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5561 for (lightindex = 0;lightindex < range;lightindex++)
5563 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5566 rtlight = &light->rtlight;
5567 rtlight->corona_visibility = 0;
5568 rtlight->corona_queryindex_visiblepixels = 0;
5569 rtlight->corona_queryindex_allpixels = 0;
5570 if (!(rtlight->flags & flag))
5572 if (rtlight->corona <= 0)
5574 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
5576 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5578 for (i = 0;i < r_refdef.scene.numlights;i++)
5580 rtlight = r_refdef.scene.lights[i];
5581 rtlight->corona_visibility = 0;
5582 rtlight->corona_queryindex_visiblepixels = 0;
5583 rtlight->corona_queryindex_allpixels = 0;
5584 if (!(rtlight->flags & flag))
5586 if (rtlight->corona <= 0)
5588 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5591 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5593 // now draw the coronas using the query data for intensity info
5594 for (lightindex = 0;lightindex < range;lightindex++)
5596 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5599 rtlight = &light->rtlight;
5600 if (rtlight->corona_visibility <= 0)
5602 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5604 for (i = 0;i < r_refdef.scene.numlights;i++)
5606 rtlight = r_refdef.scene.lights[i];
5607 if (rtlight->corona_visibility <= 0)
5609 if (gl_flashblend.integer)
5610 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
5612 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5618 static dlight_t *R_Shadow_NewWorldLight(void)
5620 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
5623 static 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)
5627 // note that style is no longer validated here, -1 is used for unstyled lights and >= MAX_LIGHTSTYLES is accepted for sake of editing rtlights files that might be out of bounds but perfectly formatted
5629 // validate parameters
5633 // copy to light properties
5634 VectorCopy(origin, light->origin);
5635 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
5636 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
5637 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
5639 light->color[0] = max(color[0], 0);
5640 light->color[1] = max(color[1], 0);
5641 light->color[2] = max(color[2], 0);
5643 light->color[0] = color[0];
5644 light->color[1] = color[1];
5645 light->color[2] = color[2];
5646 light->radius = max(radius, 0);
5647 light->style = style;
5648 light->shadow = shadowenable;
5649 light->corona = corona;
5650 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
5651 light->coronasizescale = coronasizescale;
5652 light->ambientscale = ambientscale;
5653 light->diffusescale = diffusescale;
5654 light->specularscale = specularscale;
5655 light->flags = flags;
5657 // update renderable light data
5658 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
5659 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);
5662 static void R_Shadow_FreeWorldLight(dlight_t *light)
5664 if (r_shadow_selectedlight == light)
5665 r_shadow_selectedlight = NULL;
5666 R_RTLight_Uncompile(&light->rtlight);
5667 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
5670 void R_Shadow_ClearWorldLights(void)
5674 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5675 for (lightindex = 0;lightindex < range;lightindex++)
5677 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5679 R_Shadow_FreeWorldLight(light);
5681 r_shadow_selectedlight = NULL;
5684 static void R_Shadow_SelectLight(dlight_t *light)
5686 if (r_shadow_selectedlight)
5687 r_shadow_selectedlight->selected = false;
5688 r_shadow_selectedlight = light;
5689 if (r_shadow_selectedlight)
5690 r_shadow_selectedlight->selected = true;
5693 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5695 // this is never batched (there can be only one)
5697 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
5698 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5699 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5702 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5707 skinframe_t *skinframe;
5710 // this is never batched (due to the ent parameter changing every time)
5711 // so numsurfaces == 1 and surfacelist[0] == lightnumber
5712 const dlight_t *light = (dlight_t *)ent;
5715 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
5718 VectorScale(light->color, intensity, spritecolor);
5719 if (VectorLength(spritecolor) < 0.1732f)
5720 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
5721 if (VectorLength(spritecolor) > 1.0f)
5722 VectorNormalize(spritecolor);
5724 // draw light sprite
5725 if (light->cubemapname[0] && !light->shadow)
5726 skinframe = r_editlights_sprcubemapnoshadowlight;
5727 else if (light->cubemapname[0])
5728 skinframe = r_editlights_sprcubemaplight;
5729 else if (!light->shadow)
5730 skinframe = r_editlights_sprnoshadowlight;
5732 skinframe = r_editlights_sprlight;
5734 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);
5735 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5737 // draw selection sprite if light is selected
5738 if (light->selected)
5740 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5741 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5742 // VorteX todo: add normalmode/realtime mode light overlay sprites?
5746 void R_Shadow_DrawLightSprites(void)
5750 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5751 for (lightindex = 0;lightindex < range;lightindex++)
5753 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5755 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
5757 if (!r_editlights_lockcursor)
5758 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
5761 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
5766 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
5767 if (lightindex >= range)
5769 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5772 rtlight = &light->rtlight;
5773 //if (!(rtlight->flags & flag))
5775 VectorCopy(rtlight->shadoworigin, origin);
5776 *radius = rtlight->radius;
5777 VectorCopy(rtlight->color, color);
5781 static void R_Shadow_SelectLightInView(void)
5783 float bestrating, rating, temp[3];
5787 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5791 if (r_editlights_lockcursor)
5793 for (lightindex = 0;lightindex < range;lightindex++)
5795 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5798 VectorSubtract(light->origin, r_refdef.view.origin, temp);
5799 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
5802 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
5803 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1.0f)
5805 bestrating = rating;
5810 R_Shadow_SelectLight(best);
5813 void R_Shadow_LoadWorldLights(void)
5815 int n, a, style, shadow, flags;
5816 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
5817 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
5818 if (cl.worldmodel == NULL)
5820 Con_Print("No map loaded.\n");
5823 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5824 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5834 for (;COM_Parse(t, true) && strcmp(
5835 if (COM_Parse(t, true))
5837 if (com_token[0] == '!')
5840 origin[0] = atof(com_token+1);
5843 origin[0] = atof(com_token);
5848 while (*s && *s != '\n' && *s != '\r')
5854 // check for modifier flags
5861 #if _MSC_VER >= 1400
5862 #define sscanf sscanf_s
5864 cubemapname[sizeof(cubemapname)-1] = 0;
5865 #if MAX_QPATH != 128
5866 #error update this code if MAX_QPATH changes
5868 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
5869 #if _MSC_VER >= 1400
5870 , sizeof(cubemapname)
5872 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5875 flags = LIGHTFLAG_REALTIMEMODE;
5883 coronasizescale = 0.25f;
5885 VectorClear(angles);
5888 if (a < 9 || !strcmp(cubemapname, "\"\""))
5890 // remove quotes on cubemapname
5891 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5894 namelen = strlen(cubemapname) - 2;
5895 memmove(cubemapname, cubemapname + 1, namelen);
5896 cubemapname[namelen] = '\0';
5900 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);
5903 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5911 Con_Printf("invalid rtlights file \"%s\"\n", name);
5912 Mem_Free(lightsstring);
5916 void R_Shadow_SaveWorldLights(void)
5920 size_t bufchars, bufmaxchars;
5922 char name[MAX_QPATH];
5923 char line[MAX_INPUTLINE];
5924 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5925 // I hate lines which are 3 times my screen size :( --blub
5928 if (cl.worldmodel == NULL)
5930 Con_Print("No map loaded.\n");
5933 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5934 bufchars = bufmaxchars = 0;
5936 for (lightindex = 0;lightindex < range;lightindex++)
5938 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5941 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5942 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);
5943 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5944 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]);
5946 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);
5947 if (bufchars + strlen(line) > bufmaxchars)
5949 bufmaxchars = bufchars + strlen(line) + 2048;
5951 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5955 memcpy(buf, oldbuf, bufchars);
5961 memcpy(buf + bufchars, line, strlen(line));
5962 bufchars += strlen(line);
5966 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5971 void R_Shadow_LoadLightsFile(void)
5974 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5975 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5976 if (cl.worldmodel == NULL)
5978 Con_Print("No map loaded.\n");
5981 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5982 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5990 while (*s && *s != '\n' && *s != '\r')
5996 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);
6000 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);
6003 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
6004 radius = bound(15, radius, 4096);
6005 VectorScale(color, (2.0f / (8388608.0f)), color);
6006 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6014 Con_Printf("invalid lights file \"%s\"\n", name);
6015 Mem_Free(lightsstring);
6019 // tyrlite/hmap2 light types in the delay field
6020 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
6022 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
6034 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
6035 char key[256], value[MAX_INPUTLINE];
6038 if (cl.worldmodel == NULL)
6040 Con_Print("No map loaded.\n");
6043 // try to load a .ent file first
6044 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
6045 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
6046 // and if that is not found, fall back to the bsp file entity string
6048 data = cl.worldmodel->brush.entities;
6051 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
6053 type = LIGHTTYPE_MINUSX;
6054 origin[0] = origin[1] = origin[2] = 0;
6055 originhack[0] = originhack[1] = originhack[2] = 0;
6056 angles[0] = angles[1] = angles[2] = 0;
6057 color[0] = color[1] = color[2] = 1;
6058 light[0] = light[1] = light[2] = 1;light[3] = 300;
6059 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
6069 if (!COM_ParseToken_Simple(&data, false, false, true))
6071 if (com_token[0] == '}')
6072 break; // end of entity
6073 if (com_token[0] == '_')
6074 strlcpy(key, com_token + 1, sizeof(key));
6076 strlcpy(key, com_token, sizeof(key));
6077 while (key[strlen(key)-1] == ' ') // remove trailing spaces
6078 key[strlen(key)-1] = 0;
6079 if (!COM_ParseToken_Simple(&data, false, false, true))
6081 strlcpy(value, com_token, sizeof(value));
6083 // now that we have the key pair worked out...
6084 if (!strcmp("light", key))
6086 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
6090 light[0] = vec[0] * (1.0f / 256.0f);
6091 light[1] = vec[0] * (1.0f / 256.0f);
6092 light[2] = vec[0] * (1.0f / 256.0f);
6098 light[0] = vec[0] * (1.0f / 255.0f);
6099 light[1] = vec[1] * (1.0f / 255.0f);
6100 light[2] = vec[2] * (1.0f / 255.0f);
6104 else if (!strcmp("delay", key))
6106 else if (!strcmp("origin", key))
6107 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
6108 else if (!strcmp("angle", key))
6109 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
6110 else if (!strcmp("angles", key))
6111 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
6112 else if (!strcmp("color", key))
6113 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
6114 else if (!strcmp("wait", key))
6115 fadescale = atof(value);
6116 else if (!strcmp("classname", key))
6118 if (!strncmp(value, "light", 5))
6121 if (!strcmp(value, "light_fluoro"))
6126 overridecolor[0] = 1;
6127 overridecolor[1] = 1;
6128 overridecolor[2] = 1;
6130 if (!strcmp(value, "light_fluorospark"))
6135 overridecolor[0] = 1;
6136 overridecolor[1] = 1;
6137 overridecolor[2] = 1;
6139 if (!strcmp(value, "light_globe"))
6144 overridecolor[0] = 1;
6145 overridecolor[1] = 0.8;
6146 overridecolor[2] = 0.4;
6148 if (!strcmp(value, "light_flame_large_yellow"))
6153 overridecolor[0] = 1;
6154 overridecolor[1] = 0.5;
6155 overridecolor[2] = 0.1;
6157 if (!strcmp(value, "light_flame_small_yellow"))
6162 overridecolor[0] = 1;
6163 overridecolor[1] = 0.5;
6164 overridecolor[2] = 0.1;
6166 if (!strcmp(value, "light_torch_small_white"))
6171 overridecolor[0] = 1;
6172 overridecolor[1] = 0.5;
6173 overridecolor[2] = 0.1;
6175 if (!strcmp(value, "light_torch_small_walltorch"))
6180 overridecolor[0] = 1;
6181 overridecolor[1] = 0.5;
6182 overridecolor[2] = 0.1;
6186 else if (!strcmp("style", key))
6187 style = atoi(value);
6188 else if (!strcmp("skin", key))
6189 skin = (int)atof(value);
6190 else if (!strcmp("pflags", key))
6191 pflags = (int)atof(value);
6192 //else if (!strcmp("effects", key))
6193 // effects = (int)atof(value);
6194 else if (cl.worldmodel->type == mod_brushq3)
6196 if (!strcmp("scale", key))
6197 lightscale = atof(value);
6198 if (!strcmp("fade", key))
6199 fadescale = atof(value);
6204 if (lightscale <= 0)
6208 if (color[0] == color[1] && color[0] == color[2])
6210 color[0] *= overridecolor[0];
6211 color[1] *= overridecolor[1];
6212 color[2] *= overridecolor[2];
6214 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
6215 color[0] = color[0] * light[0];
6216 color[1] = color[1] * light[1];
6217 color[2] = color[2] * light[2];
6220 case LIGHTTYPE_MINUSX:
6222 case LIGHTTYPE_RECIPX:
6224 VectorScale(color, (1.0f / 16.0f), color);
6226 case LIGHTTYPE_RECIPXX:
6228 VectorScale(color, (1.0f / 16.0f), color);
6231 case LIGHTTYPE_NONE:
6235 case LIGHTTYPE_MINUSXX:
6238 VectorAdd(origin, originhack, origin);
6240 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va(vabuf, sizeof(vabuf), "cubemaps/%i", skin) : NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6243 Mem_Free(entfiledata);
6247 static void R_Shadow_SetCursorLocationForView(void)
6250 vec3_t dest, endpos;
6252 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
6253 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true);
6254 if (trace.fraction < 1)
6256 dist = trace.fraction * r_editlights_cursordistance.value;
6257 push = r_editlights_cursorpushback.value;
6261 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
6262 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
6266 VectorClear( endpos );
6268 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6269 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6270 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6273 void R_Shadow_UpdateWorldLightSelection(void)
6275 if (r_editlights.integer)
6277 R_Shadow_SetCursorLocationForView();
6278 R_Shadow_SelectLightInView();
6281 R_Shadow_SelectLight(NULL);
6284 static void R_Shadow_EditLights_Clear_f(void)
6286 R_Shadow_ClearWorldLights();
6289 void R_Shadow_EditLights_Reload_f(void)
6293 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
6294 R_Shadow_ClearWorldLights();
6295 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
6297 R_Shadow_LoadWorldLights();
6298 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6299 R_Shadow_LoadLightsFile();
6301 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
6303 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6304 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6308 static void R_Shadow_EditLights_Save_f(void)
6312 R_Shadow_SaveWorldLights();
6315 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6317 R_Shadow_ClearWorldLights();
6318 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6321 static void R_Shadow_EditLights_ImportLightsFile_f(void)
6323 R_Shadow_ClearWorldLights();
6324 R_Shadow_LoadLightsFile();
6327 static void R_Shadow_EditLights_Spawn_f(void)
6330 if (!r_editlights.integer)
6332 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6335 if (Cmd_Argc() != 1)
6337 Con_Print("r_editlights_spawn does not take parameters\n");
6340 color[0] = color[1] = color[2] = 1;
6341 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6344 static void R_Shadow_EditLights_Edit_f(void)
6346 vec3_t origin, angles, color;
6347 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6348 int style, shadows, flags, normalmode, realtimemode;
6349 char cubemapname[MAX_INPUTLINE];
6350 if (!r_editlights.integer)
6352 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6355 if (!r_shadow_selectedlight)
6357 Con_Print("No selected light.\n");
6360 VectorCopy(r_shadow_selectedlight->origin, origin);
6361 VectorCopy(r_shadow_selectedlight->angles, angles);
6362 VectorCopy(r_shadow_selectedlight->color, color);
6363 radius = r_shadow_selectedlight->radius;
6364 style = r_shadow_selectedlight->style;
6365 if (r_shadow_selectedlight->cubemapname)
6366 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6369 shadows = r_shadow_selectedlight->shadow;
6370 corona = r_shadow_selectedlight->corona;
6371 coronasizescale = r_shadow_selectedlight->coronasizescale;
6372 ambientscale = r_shadow_selectedlight->ambientscale;
6373 diffusescale = r_shadow_selectedlight->diffusescale;
6374 specularscale = r_shadow_selectedlight->specularscale;
6375 flags = r_shadow_selectedlight->flags;
6376 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6377 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6378 if (!strcmp(Cmd_Argv(1), "origin"))
6380 if (Cmd_Argc() != 5)
6382 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6385 origin[0] = atof(Cmd_Argv(2));
6386 origin[1] = atof(Cmd_Argv(3));
6387 origin[2] = atof(Cmd_Argv(4));
6389 else if (!strcmp(Cmd_Argv(1), "originscale"))
6391 if (Cmd_Argc() != 5)
6393 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6396 origin[0] *= atof(Cmd_Argv(2));
6397 origin[1] *= atof(Cmd_Argv(3));
6398 origin[2] *= atof(Cmd_Argv(4));
6400 else if (!strcmp(Cmd_Argv(1), "originx"))
6402 if (Cmd_Argc() != 3)
6404 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6407 origin[0] = atof(Cmd_Argv(2));
6409 else if (!strcmp(Cmd_Argv(1), "originy"))
6411 if (Cmd_Argc() != 3)
6413 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6416 origin[1] = atof(Cmd_Argv(2));
6418 else if (!strcmp(Cmd_Argv(1), "originz"))
6420 if (Cmd_Argc() != 3)
6422 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6425 origin[2] = atof(Cmd_Argv(2));
6427 else if (!strcmp(Cmd_Argv(1), "move"))
6429 if (Cmd_Argc() != 5)
6431 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6434 origin[0] += atof(Cmd_Argv(2));
6435 origin[1] += atof(Cmd_Argv(3));
6436 origin[2] += atof(Cmd_Argv(4));
6438 else if (!strcmp(Cmd_Argv(1), "movex"))
6440 if (Cmd_Argc() != 3)
6442 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6445 origin[0] += atof(Cmd_Argv(2));
6447 else if (!strcmp(Cmd_Argv(1), "movey"))
6449 if (Cmd_Argc() != 3)
6451 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6454 origin[1] += atof(Cmd_Argv(2));
6456 else if (!strcmp(Cmd_Argv(1), "movez"))
6458 if (Cmd_Argc() != 3)
6460 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6463 origin[2] += atof(Cmd_Argv(2));
6465 else if (!strcmp(Cmd_Argv(1), "angles"))
6467 if (Cmd_Argc() != 5)
6469 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6472 angles[0] = atof(Cmd_Argv(2));
6473 angles[1] = atof(Cmd_Argv(3));
6474 angles[2] = atof(Cmd_Argv(4));
6476 else if (!strcmp(Cmd_Argv(1), "anglesx"))
6478 if (Cmd_Argc() != 3)
6480 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6483 angles[0] = atof(Cmd_Argv(2));
6485 else if (!strcmp(Cmd_Argv(1), "anglesy"))
6487 if (Cmd_Argc() != 3)
6489 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6492 angles[1] = atof(Cmd_Argv(2));
6494 else if (!strcmp(Cmd_Argv(1), "anglesz"))
6496 if (Cmd_Argc() != 3)
6498 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6501 angles[2] = atof(Cmd_Argv(2));
6503 else if (!strcmp(Cmd_Argv(1), "color"))
6505 if (Cmd_Argc() != 5)
6507 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
6510 color[0] = atof(Cmd_Argv(2));
6511 color[1] = atof(Cmd_Argv(3));
6512 color[2] = atof(Cmd_Argv(4));
6514 else if (!strcmp(Cmd_Argv(1), "radius"))
6516 if (Cmd_Argc() != 3)
6518 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6521 radius = atof(Cmd_Argv(2));
6523 else if (!strcmp(Cmd_Argv(1), "colorscale"))
6525 if (Cmd_Argc() == 3)
6527 double scale = atof(Cmd_Argv(2));
6534 if (Cmd_Argc() != 5)
6536 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
6539 color[0] *= atof(Cmd_Argv(2));
6540 color[1] *= atof(Cmd_Argv(3));
6541 color[2] *= atof(Cmd_Argv(4));
6544 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
6546 if (Cmd_Argc() != 3)
6548 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6551 radius *= atof(Cmd_Argv(2));
6553 else if (!strcmp(Cmd_Argv(1), "style"))
6555 if (Cmd_Argc() != 3)
6557 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6560 style = atoi(Cmd_Argv(2));
6562 else if (!strcmp(Cmd_Argv(1), "cubemap"))
6566 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6569 if (Cmd_Argc() == 3)
6570 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
6574 else if (!strcmp(Cmd_Argv(1), "shadows"))
6576 if (Cmd_Argc() != 3)
6578 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6581 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6583 else if (!strcmp(Cmd_Argv(1), "corona"))
6585 if (Cmd_Argc() != 3)
6587 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6590 corona = atof(Cmd_Argv(2));
6592 else if (!strcmp(Cmd_Argv(1), "coronasize"))
6594 if (Cmd_Argc() != 3)
6596 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6599 coronasizescale = atof(Cmd_Argv(2));
6601 else if (!strcmp(Cmd_Argv(1), "ambient"))
6603 if (Cmd_Argc() != 3)
6605 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6608 ambientscale = atof(Cmd_Argv(2));
6610 else if (!strcmp(Cmd_Argv(1), "diffuse"))
6612 if (Cmd_Argc() != 3)
6614 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6617 diffusescale = atof(Cmd_Argv(2));
6619 else if (!strcmp(Cmd_Argv(1), "specular"))
6621 if (Cmd_Argc() != 3)
6623 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6626 specularscale = atof(Cmd_Argv(2));
6628 else if (!strcmp(Cmd_Argv(1), "normalmode"))
6630 if (Cmd_Argc() != 3)
6632 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6635 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6637 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
6639 if (Cmd_Argc() != 3)
6641 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6644 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6648 Con_Print("usage: r_editlights_edit [property] [value]\n");
6649 Con_Print("Selected light's properties:\n");
6650 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6651 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6652 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6653 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
6654 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
6655 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
6656 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
6657 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
6658 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
6659 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
6660 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
6661 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
6662 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
6663 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
6666 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
6667 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6670 static void R_Shadow_EditLights_EditAll_f(void)
6673 dlight_t *light, *oldselected;
6676 if (!r_editlights.integer)
6678 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
6682 oldselected = r_shadow_selectedlight;
6683 // EditLights doesn't seem to have a "remove" command or something so:
6684 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6685 for (lightindex = 0;lightindex < range;lightindex++)
6687 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6690 R_Shadow_SelectLight(light);
6691 R_Shadow_EditLights_Edit_f();
6693 // return to old selected (to not mess editing once selection is locked)
6694 R_Shadow_SelectLight(oldselected);
6697 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
6699 int lightnumber, lightcount;
6700 size_t lightindex, range;
6705 if (!r_editlights.integer)
6708 // update cvars so QC can query them
6709 if (r_shadow_selectedlight)
6711 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6712 Cvar_SetQuick(&r_editlights_current_origin, temp);
6713 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6714 Cvar_SetQuick(&r_editlights_current_angles, temp);
6715 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6716 Cvar_SetQuick(&r_editlights_current_color, temp);
6717 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
6718 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
6719 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
6720 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
6721 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
6722 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
6723 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
6724 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
6725 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
6726 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
6727 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
6730 // draw properties on screen
6731 if (!r_editlights_drawproperties.integer)
6733 x = vid_conwidth.value - 240;
6735 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
6738 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6739 for (lightindex = 0;lightindex < range;lightindex++)
6741 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6744 if (light == r_shadow_selectedlight)
6745 lightnumber = (int)lightindex;
6748 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;
6749 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;
6751 if (r_shadow_selectedlight == NULL)
6753 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;
6754 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;
6755 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;
6756 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;
6757 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;
6758 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;
6759 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;
6760 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;
6761 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;
6762 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;
6763 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;
6764 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;
6765 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;
6766 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;
6767 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;
6770 static void R_Shadow_EditLights_ToggleShadow_f(void)
6772 if (!r_editlights.integer)
6774 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6777 if (!r_shadow_selectedlight)
6779 Con_Print("No selected light.\n");
6782 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);
6785 static void R_Shadow_EditLights_ToggleCorona_f(void)
6787 if (!r_editlights.integer)
6789 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6792 if (!r_shadow_selectedlight)
6794 Con_Print("No selected light.\n");
6797 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);
6800 static void R_Shadow_EditLights_Remove_f(void)
6802 if (!r_editlights.integer)
6804 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
6807 if (!r_shadow_selectedlight)
6809 Con_Print("No selected light.\n");
6812 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
6813 r_shadow_selectedlight = NULL;
6816 static void R_Shadow_EditLights_Help_f(void)
6819 "Documentation on r_editlights system:\n"
6821 "r_editlights : enable/disable editing mode\n"
6822 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
6823 "r_editlights_cursorpushback : push back cursor this far from surface\n"
6824 "r_editlights_cursorpushoff : push cursor off surface this far\n"
6825 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
6826 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
6828 "r_editlights_help : this help\n"
6829 "r_editlights_clear : remove all lights\n"
6830 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
6831 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
6832 "r_editlights_save : save to .rtlights file\n"
6833 "r_editlights_spawn : create a light with default settings\n"
6834 "r_editlights_edit command : edit selected light - more documentation below\n"
6835 "r_editlights_remove : remove selected light\n"
6836 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
6837 "r_editlights_importlightentitiesfrommap : reload light entities\n"
6838 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
6840 "origin x y z : set light location\n"
6841 "originx x: set x component of light location\n"
6842 "originy y: set y component of light location\n"
6843 "originz z: set z component of light location\n"
6844 "move x y z : adjust light location\n"
6845 "movex x: adjust x component of light location\n"
6846 "movey y: adjust y component of light location\n"
6847 "movez z: adjust z component of light location\n"
6848 "angles x y z : set light angles\n"
6849 "anglesx x: set x component of light angles\n"
6850 "anglesy y: set y component of light angles\n"
6851 "anglesz z: set z component of light angles\n"
6852 "color r g b : set color of light (can be brighter than 1 1 1)\n"
6853 "radius radius : set radius (size) of light\n"
6854 "colorscale grey : multiply color of light (1 does nothing)\n"
6855 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
6856 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
6857 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
6858 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
6859 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
6860 "cubemap basename : set filter cubemap of light\n"
6861 "shadows 1/0 : turn on/off shadows\n"
6862 "corona n : set corona intensity\n"
6863 "coronasize n : set corona size (0-1)\n"
6864 "ambient n : set ambient intensity (0-1)\n"
6865 "diffuse n : set diffuse intensity (0-1)\n"
6866 "specular n : set specular intensity (0-1)\n"
6867 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6868 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6869 "<nothing> : print light properties to console\n"
6873 static void R_Shadow_EditLights_CopyInfo_f(void)
6875 if (!r_editlights.integer)
6877 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
6880 if (!r_shadow_selectedlight)
6882 Con_Print("No selected light.\n");
6885 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6886 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6887 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6888 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6889 if (r_shadow_selectedlight->cubemapname)
6890 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6892 r_shadow_bufferlight.cubemapname[0] = 0;
6893 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6894 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6895 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6896 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6897 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6898 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6899 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6902 static void R_Shadow_EditLights_PasteInfo_f(void)
6904 if (!r_editlights.integer)
6906 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6909 if (!r_shadow_selectedlight)
6911 Con_Print("No selected light.\n");
6914 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);
6917 static void R_Shadow_EditLights_Lock_f(void)
6919 if (!r_editlights.integer)
6921 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6924 if (r_editlights_lockcursor)
6926 r_editlights_lockcursor = false;
6929 if (!r_shadow_selectedlight)
6931 Con_Print("No selected light to lock on.\n");
6934 r_editlights_lockcursor = true;
6937 static void R_Shadow_EditLights_Init(void)
6939 Cvar_RegisterVariable(&r_editlights);
6940 Cvar_RegisterVariable(&r_editlights_cursordistance);
6941 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6942 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6943 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6944 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6945 Cvar_RegisterVariable(&r_editlights_drawproperties);
6946 Cvar_RegisterVariable(&r_editlights_current_origin);
6947 Cvar_RegisterVariable(&r_editlights_current_angles);
6948 Cvar_RegisterVariable(&r_editlights_current_color);
6949 Cvar_RegisterVariable(&r_editlights_current_radius);
6950 Cvar_RegisterVariable(&r_editlights_current_corona);
6951 Cvar_RegisterVariable(&r_editlights_current_coronasize);
6952 Cvar_RegisterVariable(&r_editlights_current_style);
6953 Cvar_RegisterVariable(&r_editlights_current_shadows);
6954 Cvar_RegisterVariable(&r_editlights_current_cubemap);
6955 Cvar_RegisterVariable(&r_editlights_current_ambient);
6956 Cvar_RegisterVariable(&r_editlights_current_diffuse);
6957 Cvar_RegisterVariable(&r_editlights_current_specular);
6958 Cvar_RegisterVariable(&r_editlights_current_normalmode);
6959 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
6960 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6961 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6962 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)");
6963 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6964 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6965 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6966 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)");
6967 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6968 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6969 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6970 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6971 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6972 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6973 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)");
6974 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6980 =============================================================================
6984 =============================================================================
6987 void R_LightPoint(float *color, const vec3_t p, const int flags)
6989 int i, numlights, flag;
6990 float f, relativepoint[3], dist, dist2, lightradius2;
6995 if (r_fullbright.integer)
6997 VectorSet(color, 1, 1, 1);
7003 if (flags & LP_LIGHTMAP)
7005 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7007 VectorClear(diffuse);
7008 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, color, diffuse, n);
7009 VectorAdd(color, diffuse, color);
7012 VectorSet(color, 1, 1, 1);
7013 color[0] += r_refdef.scene.ambient;
7014 color[1] += r_refdef.scene.ambient;
7015 color[2] += r_refdef.scene.ambient;
7018 if (flags & LP_RTWORLD)
7020 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7021 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7022 for (i = 0; i < numlights; i++)
7024 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7027 light = &dlight->rtlight;
7028 if (!(light->flags & flag))
7031 lightradius2 = light->radius * light->radius;
7032 VectorSubtract(light->shadoworigin, p, relativepoint);
7033 dist2 = VectorLength2(relativepoint);
7034 if (dist2 >= lightradius2)
7036 dist = sqrt(dist2) / light->radius;
7037 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7040 // todo: add to both ambient and diffuse
7041 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1)
7042 VectorMA(color, f, light->currentcolor, color);
7045 if (flags & LP_DYNLIGHT)
7048 for (i = 0;i < r_refdef.scene.numlights;i++)
7050 light = r_refdef.scene.lights[i];
7052 lightradius2 = light->radius * light->radius;
7053 VectorSubtract(light->shadoworigin, p, relativepoint);
7054 dist2 = VectorLength2(relativepoint);
7055 if (dist2 >= lightradius2)
7057 dist = sqrt(dist2) / light->radius;
7058 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7061 // todo: add to both ambient and diffuse
7062 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1)
7063 VectorMA(color, f, light->color, color);
7068 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
7070 int i, numlights, flag;
7073 float relativepoint[3];
7082 if (r_fullbright.integer)
7084 VectorSet(ambient, 1, 1, 1);
7085 VectorClear(diffuse);
7086 VectorClear(lightdir);
7090 if (flags == LP_LIGHTMAP)
7092 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7093 VectorClear(diffuse);
7094 VectorClear(lightdir);
7095 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7096 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
7098 VectorSet(ambient, 1, 1, 1);
7102 memset(sample, 0, sizeof(sample));
7103 VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7105 if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7108 VectorClear(tempambient);
7110 VectorClear(relativepoint);
7111 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
7112 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
7113 VectorScale(color, r_refdef.lightmapintensity, color);
7114 VectorAdd(sample, tempambient, sample);
7115 VectorMA(sample , 0.5f , color, sample );
7116 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7117 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7118 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7119 // calculate a weighted average light direction as well
7120 intensity = VectorLength(color);
7121 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7124 if (flags & LP_RTWORLD)
7126 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7127 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7128 for (i = 0; i < numlights; i++)
7130 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7133 light = &dlight->rtlight;
7134 if (!(light->flags & flag))
7137 lightradius2 = light->radius * light->radius;
7138 VectorSubtract(light->shadoworigin, p, relativepoint);
7139 dist2 = VectorLength2(relativepoint);
7140 if (dist2 >= lightradius2)
7142 dist = sqrt(dist2) / light->radius;
7143 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
7144 if (intensity <= 0.0f)
7146 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
7148 // scale down intensity to add to both ambient and diffuse
7149 //intensity *= 0.5f;
7150 VectorNormalize(relativepoint);
7151 VectorScale(light->currentcolor, intensity, color);
7152 VectorMA(sample , 0.5f , color, sample );
7153 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7154 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7155 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7156 // calculate a weighted average light direction as well
7157 intensity *= VectorLength(color);
7158 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7160 // FIXME: sample bouncegrid too!
7163 if (flags & LP_DYNLIGHT)
7166 for (i = 0;i < r_refdef.scene.numlights;i++)
7168 light = r_refdef.scene.lights[i];
7170 lightradius2 = light->radius * light->radius;
7171 VectorSubtract(light->shadoworigin, p, relativepoint);
7172 dist2 = VectorLength2(relativepoint);
7173 if (dist2 >= lightradius2)
7175 dist = sqrt(dist2) / light->radius;
7176 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
7177 if (intensity <= 0.0f)
7179 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
7181 // scale down intensity to add to both ambient and diffuse
7182 //intensity *= 0.5f;
7183 VectorNormalize(relativepoint);
7184 VectorScale(light->currentcolor, intensity, color);
7185 VectorMA(sample , 0.5f , color, sample );
7186 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7187 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7188 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7189 // calculate a weighted average light direction as well
7190 intensity *= VectorLength(color);
7191 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7195 // calculate the direction we'll use to reduce the sample to a directional light source
7196 VectorCopy(sample + 12, dir);
7197 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
7198 VectorNormalize(dir);
7199 // extract the diffuse color along the chosen direction and scale it
7200 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
7201 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
7202 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
7203 // subtract some of diffuse from ambient
7204 VectorMA(sample, -0.333f, diffuse, ambient);
7205 // store the normalized lightdir
7206 VectorCopy(dir, lightdir);