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_coronas = {CVAR_SAVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
354 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"};
355 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!"};
356 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
357 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
358 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
359 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
360 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
361 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
362 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
363 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
364 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
365 cvar_t r_editlights_drawproperties = {0, "r_editlights_drawproperties", "1", "draw properties of currently selected light"};
366 cvar_t r_editlights_current_origin = {0, "r_editlights_current_origin", "0 0 0", "origin of selected light"};
367 cvar_t r_editlights_current_angles = {0, "r_editlights_current_angles", "0 0 0", "angles of selected light"};
368 cvar_t r_editlights_current_color = {0, "r_editlights_current_color", "1 1 1", "color of selected light"};
369 cvar_t r_editlights_current_radius = {0, "r_editlights_current_radius", "0", "radius of selected light"};
370 cvar_t r_editlights_current_corona = {0, "r_editlights_current_corona", "0", "corona intensity of selected light"};
371 cvar_t r_editlights_current_coronasize = {0, "r_editlights_current_coronasize", "0", "corona size of selected light"};
372 cvar_t r_editlights_current_style = {0, "r_editlights_current_style", "0", "style of selected light"};
373 cvar_t r_editlights_current_shadows = {0, "r_editlights_current_shadows", "0", "shadows flag of selected light"};
374 cvar_t r_editlights_current_cubemap = {0, "r_editlights_current_cubemap", "0", "cubemap of selected light"};
375 cvar_t r_editlights_current_ambient = {0, "r_editlights_current_ambient", "0", "ambient intensity of selected light"};
376 cvar_t r_editlights_current_diffuse = {0, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"};
377 cvar_t r_editlights_current_specular = {0, "r_editlights_current_specular", "1", "specular intensity of selected light"};
378 cvar_t r_editlights_current_normalmode = {0, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"};
379 cvar_t r_editlights_current_realtimemode = {0, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"};
381 r_shadow_bouncegrid_state_t r_shadow_bouncegrid_state;
383 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
384 #define ATTENTABLESIZE 256
385 // 1D gradient, 2D circle and 3D sphere attenuation textures
386 #define ATTEN1DSIZE 32
387 #define ATTEN2DSIZE 64
388 #define ATTEN3DSIZE 32
390 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
391 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
392 static float r_shadow_attentable[ATTENTABLESIZE+1];
394 rtlight_t *r_shadow_compilingrtlight;
395 static memexpandablearray_t r_shadow_worldlightsarray;
396 dlight_t *r_shadow_selectedlight;
397 dlight_t r_shadow_bufferlight;
398 vec3_t r_editlights_cursorlocation;
399 qboolean r_editlights_lockcursor;
401 extern int con_vislines;
403 void R_Shadow_UncompileWorldLights(void);
404 void R_Shadow_ClearWorldLights(void);
405 void R_Shadow_SaveWorldLights(void);
406 void R_Shadow_LoadWorldLights(void);
407 void R_Shadow_LoadLightsFile(void);
408 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
409 void R_Shadow_EditLights_Reload_f(void);
410 void R_Shadow_ValidateCvars(void);
411 static void R_Shadow_MakeTextures(void);
413 #define EDLIGHTSPRSIZE 8
414 skinframe_t *r_editlights_sprcursor;
415 skinframe_t *r_editlights_sprlight;
416 skinframe_t *r_editlights_sprnoshadowlight;
417 skinframe_t *r_editlights_sprcubemaplight;
418 skinframe_t *r_editlights_sprcubemapnoshadowlight;
419 skinframe_t *r_editlights_sprselection;
421 static void R_Shadow_SetShadowMode(void)
423 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
424 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
425 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
426 r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
427 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
428 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
429 r_shadow_shadowmaplod = -1;
430 r_shadow_shadowmapsize = 0;
431 r_shadow_shadowmapsampler = false;
432 r_shadow_shadowmappcf = 0;
433 r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
434 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
435 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
437 switch(vid.renderpath)
439 case RENDERPATH_GL20:
440 if(r_shadow_shadowmapfilterquality < 0)
442 if (!r_fb.usedepthtextures)
443 r_shadow_shadowmappcf = 1;
444 else if((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && vid.support.arb_shadow && r_shadow_shadowmapshadowsampler)
446 r_shadow_shadowmapsampler = true;
447 r_shadow_shadowmappcf = 1;
449 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
450 r_shadow_shadowmappcf = 1;
451 else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa"))
452 r_shadow_shadowmappcf = 1;
454 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
458 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
459 switch (r_shadow_shadowmapfilterquality)
464 r_shadow_shadowmappcf = 1;
467 r_shadow_shadowmappcf = 1;
470 r_shadow_shadowmappcf = 2;
474 if (!r_fb.usedepthtextures)
475 r_shadow_shadowmapsampler = false;
476 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
478 case RENDERPATH_D3D9:
479 case RENDERPATH_D3D10:
480 case RENDERPATH_D3D11:
481 case RENDERPATH_SOFT:
482 r_shadow_shadowmapsampler = false;
483 r_shadow_shadowmappcf = 1;
484 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
486 case RENDERPATH_GL11:
487 case RENDERPATH_GL13:
488 case RENDERPATH_GLES1:
489 case RENDERPATH_GLES2:
494 if(R_CompileShader_CheckStaticParms())
498 qboolean R_Shadow_ShadowMappingEnabled(void)
500 switch (r_shadow_shadowmode)
502 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
509 static void R_Shadow_FreeShadowMaps(void)
511 R_Shadow_SetShadowMode();
513 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
517 if (r_shadow_shadowmap2ddepthtexture)
518 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
519 r_shadow_shadowmap2ddepthtexture = NULL;
521 if (r_shadow_shadowmap2ddepthbuffer)
522 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
523 r_shadow_shadowmap2ddepthbuffer = NULL;
525 if (r_shadow_shadowmapvsdcttexture)
526 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
527 r_shadow_shadowmapvsdcttexture = NULL;
530 static void r_shadow_start(void)
532 // allocate vertex processing arrays
533 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
534 r_shadow_attenuationgradienttexture = NULL;
535 r_shadow_attenuation2dtexture = NULL;
536 r_shadow_attenuation3dtexture = NULL;
537 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
538 r_shadow_shadowmap2ddepthtexture = NULL;
539 r_shadow_shadowmap2ddepthbuffer = NULL;
540 r_shadow_shadowmapvsdcttexture = NULL;
541 r_shadow_shadowmapmaxsize = 0;
542 r_shadow_shadowmapsize = 0;
543 r_shadow_shadowmaplod = 0;
544 r_shadow_shadowmapfilterquality = -1;
545 r_shadow_shadowmapdepthbits = 0;
546 r_shadow_shadowmapvsdct = false;
547 r_shadow_shadowmapsampler = false;
548 r_shadow_shadowmappcf = 0;
551 R_Shadow_FreeShadowMaps();
553 r_shadow_texturepool = NULL;
554 r_shadow_filters_texturepool = NULL;
555 R_Shadow_ValidateCvars();
556 R_Shadow_MakeTextures();
557 maxshadowtriangles = 0;
558 shadowelements = NULL;
559 maxshadowvertices = 0;
560 shadowvertex3f = NULL;
568 shadowmarklist = NULL;
573 shadowsideslist = NULL;
574 r_shadow_buffer_numleafpvsbytes = 0;
575 r_shadow_buffer_visitingleafpvs = NULL;
576 r_shadow_buffer_leafpvs = NULL;
577 r_shadow_buffer_leaflist = NULL;
578 r_shadow_buffer_numsurfacepvsbytes = 0;
579 r_shadow_buffer_surfacepvs = NULL;
580 r_shadow_buffer_surfacelist = NULL;
581 r_shadow_buffer_surfacesides = NULL;
582 r_shadow_buffer_numshadowtrispvsbytes = 0;
583 r_shadow_buffer_shadowtrispvs = NULL;
584 r_shadow_buffer_numlighttrispvsbytes = 0;
585 r_shadow_buffer_lighttrispvs = NULL;
587 r_shadow_usingdeferredprepass = false;
588 r_shadow_prepass_width = r_shadow_prepass_height = 0;
590 // determine renderpath specific capabilities, we don't need to figure
591 // these out per frame...
592 switch(vid.renderpath)
594 case RENDERPATH_GL20:
595 r_shadow_bouncegrid_state.allowdirectionalshading = true;
596 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
598 case RENDERPATH_GLES2:
599 // for performance reasons, do not use directional shading on GLES devices
600 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
602 // these renderpaths do not currently have the code to display the bouncegrid, so disable it on them...
603 case RENDERPATH_GL11:
604 case RENDERPATH_GL13:
605 case RENDERPATH_GLES1:
606 case RENDERPATH_SOFT:
607 case RENDERPATH_D3D9:
608 case RENDERPATH_D3D10:
609 case RENDERPATH_D3D11:
614 static void R_Shadow_FreeDeferred(void);
615 static void r_shadow_shutdown(void)
618 R_Shadow_UncompileWorldLights();
620 R_Shadow_FreeShadowMaps();
622 r_shadow_usingdeferredprepass = false;
623 if (r_shadow_prepass_width)
624 R_Shadow_FreeDeferred();
625 r_shadow_prepass_width = r_shadow_prepass_height = 0;
628 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
629 r_shadow_attenuationgradienttexture = NULL;
630 r_shadow_attenuation2dtexture = NULL;
631 r_shadow_attenuation3dtexture = NULL;
632 R_FreeTexturePool(&r_shadow_texturepool);
633 R_FreeTexturePool(&r_shadow_filters_texturepool);
634 maxshadowtriangles = 0;
636 Mem_Free(shadowelements);
637 shadowelements = NULL;
639 Mem_Free(shadowvertex3f);
640 shadowvertex3f = NULL;
643 Mem_Free(vertexupdate);
646 Mem_Free(vertexremap);
652 Mem_Free(shadowmark);
655 Mem_Free(shadowmarklist);
656 shadowmarklist = NULL;
661 Mem_Free(shadowsides);
664 Mem_Free(shadowsideslist);
665 shadowsideslist = NULL;
666 r_shadow_buffer_numleafpvsbytes = 0;
667 if (r_shadow_buffer_visitingleafpvs)
668 Mem_Free(r_shadow_buffer_visitingleafpvs);
669 r_shadow_buffer_visitingleafpvs = NULL;
670 if (r_shadow_buffer_leafpvs)
671 Mem_Free(r_shadow_buffer_leafpvs);
672 r_shadow_buffer_leafpvs = NULL;
673 if (r_shadow_buffer_leaflist)
674 Mem_Free(r_shadow_buffer_leaflist);
675 r_shadow_buffer_leaflist = NULL;
676 r_shadow_buffer_numsurfacepvsbytes = 0;
677 if (r_shadow_buffer_surfacepvs)
678 Mem_Free(r_shadow_buffer_surfacepvs);
679 r_shadow_buffer_surfacepvs = NULL;
680 if (r_shadow_buffer_surfacelist)
681 Mem_Free(r_shadow_buffer_surfacelist);
682 r_shadow_buffer_surfacelist = NULL;
683 if (r_shadow_buffer_surfacesides)
684 Mem_Free(r_shadow_buffer_surfacesides);
685 r_shadow_buffer_surfacesides = NULL;
686 r_shadow_buffer_numshadowtrispvsbytes = 0;
687 if (r_shadow_buffer_shadowtrispvs)
688 Mem_Free(r_shadow_buffer_shadowtrispvs);
689 r_shadow_buffer_numlighttrispvsbytes = 0;
690 if (r_shadow_buffer_lighttrispvs)
691 Mem_Free(r_shadow_buffer_lighttrispvs);
694 static void r_shadow_newmap(void)
696 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
697 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
698 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
699 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
700 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
701 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
702 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
703 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
704 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
705 R_Shadow_EditLights_Reload_f();
708 void R_Shadow_Init(void)
710 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
711 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
712 Cvar_RegisterVariable(&r_shadow_usebihculling);
713 Cvar_RegisterVariable(&r_shadow_usenormalmap);
714 Cvar_RegisterVariable(&r_shadow_debuglight);
715 Cvar_RegisterVariable(&r_shadow_deferred);
716 Cvar_RegisterVariable(&r_shadow_gloss);
717 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
718 Cvar_RegisterVariable(&r_shadow_glossintensity);
719 Cvar_RegisterVariable(&r_shadow_glossexponent);
720 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
721 Cvar_RegisterVariable(&r_shadow_glossexact);
722 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
723 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
724 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
725 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
726 Cvar_RegisterVariable(&r_shadow_projectdistance);
727 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
728 Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
729 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
730 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
731 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
732 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
733 Cvar_RegisterVariable(&r_shadow_realtime_world);
734 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
735 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
736 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
737 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
738 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
739 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
740 Cvar_RegisterVariable(&r_shadow_scissor);
741 Cvar_RegisterVariable(&r_shadow_shadowmapping);
742 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
743 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
744 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
745 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
746 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
747 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
748 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
749 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
750 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
751 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
752 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
753 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
754 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
755 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
756 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
757 Cvar_RegisterVariable(&r_shadow_polygonfactor);
758 Cvar_RegisterVariable(&r_shadow_polygonoffset);
759 Cvar_RegisterVariable(&r_shadow_texture3d);
760 Cvar_RegisterVariable(&r_shadow_bouncegrid);
761 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
762 Cvar_RegisterVariable(&r_shadow_bouncegrid_directionalshading);
763 Cvar_RegisterVariable(&r_shadow_bouncegrid_dlightparticlemultiplier);
764 Cvar_RegisterVariable(&r_shadow_bouncegrid_hitmodels);
765 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
766 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
767 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightradiusscale);
768 Cvar_RegisterVariable(&r_shadow_bouncegrid_maxbounce);
769 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
770 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
771 Cvar_RegisterVariable(&r_shadow_bouncegrid_maxphotons);
772 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensityperphoton);
773 Cvar_RegisterVariable(&r_shadow_bouncegrid_spacing);
774 Cvar_RegisterVariable(&r_shadow_bouncegrid_stablerandom);
775 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
776 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
777 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
778 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
779 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxphotons);
780 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_intensityperphoton);
781 Cvar_RegisterVariable(&r_shadow_bouncegrid_updateinterval);
782 Cvar_RegisterVariable(&r_shadow_bouncegrid_x);
783 Cvar_RegisterVariable(&r_shadow_bouncegrid_y);
784 Cvar_RegisterVariable(&r_shadow_bouncegrid_z);
785 Cvar_RegisterVariable(&r_coronas);
786 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
787 Cvar_RegisterVariable(&r_coronas_occlusionquery);
788 Cvar_RegisterVariable(&gl_flashblend);
789 Cvar_RegisterVariable(&gl_ext_separatestencil);
790 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
791 R_Shadow_EditLights_Init();
792 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
793 maxshadowtriangles = 0;
794 shadowelements = NULL;
795 maxshadowvertices = 0;
796 shadowvertex3f = NULL;
804 shadowmarklist = NULL;
809 shadowsideslist = NULL;
810 r_shadow_buffer_numleafpvsbytes = 0;
811 r_shadow_buffer_visitingleafpvs = NULL;
812 r_shadow_buffer_leafpvs = NULL;
813 r_shadow_buffer_leaflist = NULL;
814 r_shadow_buffer_numsurfacepvsbytes = 0;
815 r_shadow_buffer_surfacepvs = NULL;
816 r_shadow_buffer_surfacelist = NULL;
817 r_shadow_buffer_surfacesides = NULL;
818 r_shadow_buffer_shadowtrispvs = NULL;
819 r_shadow_buffer_lighttrispvs = NULL;
820 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
823 matrix4x4_t matrix_attenuationxyz =
826 {0.5, 0.0, 0.0, 0.5},
827 {0.0, 0.5, 0.0, 0.5},
828 {0.0, 0.0, 0.5, 0.5},
833 matrix4x4_t matrix_attenuationz =
836 {0.0, 0.0, 0.5, 0.5},
837 {0.0, 0.0, 0.0, 0.5},
838 {0.0, 0.0, 0.0, 0.5},
843 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
845 numvertices = ((numvertices + 255) & ~255) * vertscale;
846 numtriangles = ((numtriangles + 255) & ~255) * triscale;
847 // make sure shadowelements is big enough for this volume
848 if (maxshadowtriangles < numtriangles)
850 maxshadowtriangles = numtriangles;
852 Mem_Free(shadowelements);
853 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
855 // make sure shadowvertex3f is big enough for this volume
856 if (maxshadowvertices < numvertices)
858 maxshadowvertices = numvertices;
860 Mem_Free(shadowvertex3f);
861 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
865 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
867 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
868 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
869 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
870 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
871 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
873 if (r_shadow_buffer_visitingleafpvs)
874 Mem_Free(r_shadow_buffer_visitingleafpvs);
875 if (r_shadow_buffer_leafpvs)
876 Mem_Free(r_shadow_buffer_leafpvs);
877 if (r_shadow_buffer_leaflist)
878 Mem_Free(r_shadow_buffer_leaflist);
879 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
880 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
881 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
882 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
884 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
886 if (r_shadow_buffer_surfacepvs)
887 Mem_Free(r_shadow_buffer_surfacepvs);
888 if (r_shadow_buffer_surfacelist)
889 Mem_Free(r_shadow_buffer_surfacelist);
890 if (r_shadow_buffer_surfacesides)
891 Mem_Free(r_shadow_buffer_surfacesides);
892 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
893 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
894 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
895 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
897 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
899 if (r_shadow_buffer_shadowtrispvs)
900 Mem_Free(r_shadow_buffer_shadowtrispvs);
901 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
902 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
904 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
906 if (r_shadow_buffer_lighttrispvs)
907 Mem_Free(r_shadow_buffer_lighttrispvs);
908 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
909 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
913 void R_Shadow_PrepareShadowMark(int numtris)
915 // make sure shadowmark is big enough for this volume
916 if (maxshadowmark < numtris)
918 maxshadowmark = numtris;
920 Mem_Free(shadowmark);
922 Mem_Free(shadowmarklist);
923 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
924 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
928 // if shadowmarkcount wrapped we clear the array and adjust accordingly
929 if (shadowmarkcount == 0)
932 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
937 void R_Shadow_PrepareShadowSides(int numtris)
939 if (maxshadowsides < numtris)
941 maxshadowsides = numtris;
943 Mem_Free(shadowsides);
945 Mem_Free(shadowsideslist);
946 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
947 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
952 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)
955 int outtriangles = 0, outvertices = 0;
958 float ratio, direction[3], projectvector[3];
960 if (projectdirection)
961 VectorScale(projectdirection, projectdistance, projectvector);
963 VectorClear(projectvector);
965 // create the vertices
966 if (projectdirection)
968 for (i = 0;i < numshadowmarktris;i++)
970 element = inelement3i + shadowmarktris[i] * 3;
971 for (j = 0;j < 3;j++)
973 if (vertexupdate[element[j]] != vertexupdatenum)
975 vertexupdate[element[j]] = vertexupdatenum;
976 vertexremap[element[j]] = outvertices;
977 vertex = invertex3f + element[j] * 3;
978 // project one copy of the vertex according to projectvector
979 VectorCopy(vertex, outvertex3f);
980 VectorAdd(vertex, projectvector, (outvertex3f + 3));
989 for (i = 0;i < numshadowmarktris;i++)
991 element = inelement3i + shadowmarktris[i] * 3;
992 for (j = 0;j < 3;j++)
994 if (vertexupdate[element[j]] != vertexupdatenum)
996 vertexupdate[element[j]] = vertexupdatenum;
997 vertexremap[element[j]] = outvertices;
998 vertex = invertex3f + element[j] * 3;
999 // project one copy of the vertex to the sphere radius of the light
1000 // (FIXME: would projecting it to the light box be better?)
1001 VectorSubtract(vertex, projectorigin, direction);
1002 ratio = projectdistance / VectorLength(direction);
1003 VectorCopy(vertex, outvertex3f);
1004 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1012 if (r_shadow_frontsidecasting.integer)
1014 for (i = 0;i < numshadowmarktris;i++)
1016 int remappedelement[3];
1018 const int *neighbortriangle;
1020 markindex = shadowmarktris[i] * 3;
1021 element = inelement3i + markindex;
1022 neighbortriangle = inneighbor3i + markindex;
1023 // output the front and back triangles
1024 outelement3i[0] = vertexremap[element[0]];
1025 outelement3i[1] = vertexremap[element[1]];
1026 outelement3i[2] = vertexremap[element[2]];
1027 outelement3i[3] = vertexremap[element[2]] + 1;
1028 outelement3i[4] = vertexremap[element[1]] + 1;
1029 outelement3i[5] = vertexremap[element[0]] + 1;
1033 // output the sides (facing outward from this triangle)
1034 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1036 remappedelement[0] = vertexremap[element[0]];
1037 remappedelement[1] = vertexremap[element[1]];
1038 outelement3i[0] = remappedelement[1];
1039 outelement3i[1] = remappedelement[0];
1040 outelement3i[2] = remappedelement[0] + 1;
1041 outelement3i[3] = remappedelement[1];
1042 outelement3i[4] = remappedelement[0] + 1;
1043 outelement3i[5] = remappedelement[1] + 1;
1048 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1050 remappedelement[1] = vertexremap[element[1]];
1051 remappedelement[2] = vertexremap[element[2]];
1052 outelement3i[0] = remappedelement[2];
1053 outelement3i[1] = remappedelement[1];
1054 outelement3i[2] = remappedelement[1] + 1;
1055 outelement3i[3] = remappedelement[2];
1056 outelement3i[4] = remappedelement[1] + 1;
1057 outelement3i[5] = remappedelement[2] + 1;
1062 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1064 remappedelement[0] = vertexremap[element[0]];
1065 remappedelement[2] = vertexremap[element[2]];
1066 outelement3i[0] = remappedelement[0];
1067 outelement3i[1] = remappedelement[2];
1068 outelement3i[2] = remappedelement[2] + 1;
1069 outelement3i[3] = remappedelement[0];
1070 outelement3i[4] = remappedelement[2] + 1;
1071 outelement3i[5] = remappedelement[0] + 1;
1080 for (i = 0;i < numshadowmarktris;i++)
1082 int remappedelement[3];
1084 const int *neighbortriangle;
1086 markindex = shadowmarktris[i] * 3;
1087 element = inelement3i + markindex;
1088 neighbortriangle = inneighbor3i + markindex;
1089 // output the front and back triangles
1090 outelement3i[0] = vertexremap[element[2]];
1091 outelement3i[1] = vertexremap[element[1]];
1092 outelement3i[2] = vertexremap[element[0]];
1093 outelement3i[3] = vertexremap[element[0]] + 1;
1094 outelement3i[4] = vertexremap[element[1]] + 1;
1095 outelement3i[5] = vertexremap[element[2]] + 1;
1099 // output the sides (facing outward from this triangle)
1100 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1102 remappedelement[0] = vertexremap[element[0]];
1103 remappedelement[1] = vertexremap[element[1]];
1104 outelement3i[0] = remappedelement[0];
1105 outelement3i[1] = remappedelement[1];
1106 outelement3i[2] = remappedelement[1] + 1;
1107 outelement3i[3] = remappedelement[0];
1108 outelement3i[4] = remappedelement[1] + 1;
1109 outelement3i[5] = remappedelement[0] + 1;
1114 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1116 remappedelement[1] = vertexremap[element[1]];
1117 remappedelement[2] = vertexremap[element[2]];
1118 outelement3i[0] = remappedelement[1];
1119 outelement3i[1] = remappedelement[2];
1120 outelement3i[2] = remappedelement[2] + 1;
1121 outelement3i[3] = remappedelement[1];
1122 outelement3i[4] = remappedelement[2] + 1;
1123 outelement3i[5] = remappedelement[1] + 1;
1128 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1130 remappedelement[0] = vertexremap[element[0]];
1131 remappedelement[2] = vertexremap[element[2]];
1132 outelement3i[0] = remappedelement[2];
1133 outelement3i[1] = remappedelement[0];
1134 outelement3i[2] = remappedelement[0] + 1;
1135 outelement3i[3] = remappedelement[2];
1136 outelement3i[4] = remappedelement[0] + 1;
1137 outelement3i[5] = remappedelement[2] + 1;
1145 *outnumvertices = outvertices;
1146 return outtriangles;
1149 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)
1152 int outtriangles = 0, outvertices = 0;
1154 const float *vertex;
1155 float ratio, direction[3], projectvector[3];
1158 if (projectdirection)
1159 VectorScale(projectdirection, projectdistance, projectvector);
1161 VectorClear(projectvector);
1163 for (i = 0;i < numshadowmarktris;i++)
1165 int remappedelement[3];
1167 const int *neighbortriangle;
1169 markindex = shadowmarktris[i] * 3;
1170 neighbortriangle = inneighbor3i + markindex;
1171 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1172 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1173 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1174 if (side[0] + side[1] + side[2] == 0)
1178 element = inelement3i + markindex;
1180 // create the vertices
1181 for (j = 0;j < 3;j++)
1183 if (side[j] + side[j+1] == 0)
1186 if (vertexupdate[k] != vertexupdatenum)
1188 vertexupdate[k] = vertexupdatenum;
1189 vertexremap[k] = outvertices;
1190 vertex = invertex3f + k * 3;
1191 VectorCopy(vertex, outvertex3f);
1192 if (projectdirection)
1194 // project one copy of the vertex according to projectvector
1195 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1199 // project one copy of the vertex to the sphere radius of the light
1200 // (FIXME: would projecting it to the light box be better?)
1201 VectorSubtract(vertex, projectorigin, direction);
1202 ratio = projectdistance / VectorLength(direction);
1203 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1210 // output the sides (facing outward from this triangle)
1213 remappedelement[0] = vertexremap[element[0]];
1214 remappedelement[1] = vertexremap[element[1]];
1215 outelement3i[0] = remappedelement[1];
1216 outelement3i[1] = remappedelement[0];
1217 outelement3i[2] = remappedelement[0] + 1;
1218 outelement3i[3] = remappedelement[1];
1219 outelement3i[4] = remappedelement[0] + 1;
1220 outelement3i[5] = remappedelement[1] + 1;
1227 remappedelement[1] = vertexremap[element[1]];
1228 remappedelement[2] = vertexremap[element[2]];
1229 outelement3i[0] = remappedelement[2];
1230 outelement3i[1] = remappedelement[1];
1231 outelement3i[2] = remappedelement[1] + 1;
1232 outelement3i[3] = remappedelement[2];
1233 outelement3i[4] = remappedelement[1] + 1;
1234 outelement3i[5] = remappedelement[2] + 1;
1241 remappedelement[0] = vertexremap[element[0]];
1242 remappedelement[2] = vertexremap[element[2]];
1243 outelement3i[0] = remappedelement[0];
1244 outelement3i[1] = remappedelement[2];
1245 outelement3i[2] = remappedelement[2] + 1;
1246 outelement3i[3] = remappedelement[0];
1247 outelement3i[4] = remappedelement[2] + 1;
1248 outelement3i[5] = remappedelement[0] + 1;
1255 *outnumvertices = outvertices;
1256 return outtriangles;
1259 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)
1265 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1267 tend = firsttriangle + numtris;
1268 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1270 // surface box entirely inside light box, no box cull
1271 if (projectdirection)
1273 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1275 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1276 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1277 shadowmarklist[numshadowmark++] = t;
1282 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1283 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1284 shadowmarklist[numshadowmark++] = t;
1289 // surface box not entirely inside light box, cull each triangle
1290 if (projectdirection)
1292 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1294 v[0] = invertex3f + e[0] * 3;
1295 v[1] = invertex3f + e[1] * 3;
1296 v[2] = invertex3f + e[2] * 3;
1297 TriangleNormal(v[0], v[1], v[2], normal);
1298 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1299 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1300 shadowmarklist[numshadowmark++] = t;
1305 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1307 v[0] = invertex3f + e[0] * 3;
1308 v[1] = invertex3f + e[1] * 3;
1309 v[2] = invertex3f + e[2] * 3;
1310 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1311 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1312 shadowmarklist[numshadowmark++] = t;
1318 static qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1323 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1325 // check if the shadow volume intersects the near plane
1327 // a ray between the eye and light origin may intersect the caster,
1328 // indicating that the shadow may touch the eye location, however we must
1329 // test the near plane (a polygon), not merely the eye location, so it is
1330 // easiest to enlarge the caster bounding shape slightly for this.
1336 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)
1338 int i, tris, outverts;
1339 if (projectdistance < 0.1)
1341 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1344 if (!numverts || !nummarktris)
1346 // make sure shadowelements is big enough for this volume
1347 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1348 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1350 if (maxvertexupdate < numverts)
1352 maxvertexupdate = numverts;
1354 Mem_Free(vertexupdate);
1356 Mem_Free(vertexremap);
1357 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1358 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1359 vertexupdatenum = 0;
1362 if (vertexupdatenum == 0)
1364 vertexupdatenum = 1;
1365 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1366 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1369 for (i = 0;i < nummarktris;i++)
1370 shadowmark[marktris[i]] = shadowmarkcount;
1372 if (r_shadow_compilingrtlight)
1374 // if we're compiling an rtlight, capture the mesh
1375 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1376 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1377 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1378 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1380 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1382 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1383 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1384 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1388 // decide which type of shadow to generate and set stencil mode
1389 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1390 // generate the sides or a solid volume, depending on type
1391 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1392 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1394 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1395 r_refdef.stats[r_stat_lights_dynamicshadowtriangles] += tris;
1396 r_refdef.stats[r_stat_lights_shadowtriangles] += tris;
1397 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1399 // increment stencil if frontface is infront of depthbuffer
1400 GL_CullFace(r_refdef.view.cullface_front);
1401 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1402 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1403 // decrement stencil if backface is infront of depthbuffer
1404 GL_CullFace(r_refdef.view.cullface_back);
1405 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1407 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1409 // decrement stencil if backface is behind depthbuffer
1410 GL_CullFace(r_refdef.view.cullface_front);
1411 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1412 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1413 // increment stencil if frontface is behind depthbuffer
1414 GL_CullFace(r_refdef.view.cullface_back);
1415 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1417 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1418 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1422 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1424 // p1, p2, p3 are in the cubemap's local coordinate system
1425 // bias = border/(size - border)
1428 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1429 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1430 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1431 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1433 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1434 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1435 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1436 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1438 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1439 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1440 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1442 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1443 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1444 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1445 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1447 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1448 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1449 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1450 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1452 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1453 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1454 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1456 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1457 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1458 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1459 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1461 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1462 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1463 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1464 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1466 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1467 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1468 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1473 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1475 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1476 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1479 VectorSubtract(maxs, mins, radius);
1480 VectorScale(radius, 0.5f, radius);
1481 VectorAdd(mins, radius, center);
1482 Matrix4x4_Transform(worldtolight, center, lightcenter);
1483 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1484 VectorSubtract(lightcenter, lightradius, pmin);
1485 VectorAdd(lightcenter, lightradius, pmax);
1487 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1488 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1489 if(ap1 > bias*an1 && ap2 > bias*an2)
1491 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1492 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1493 if(an1 > bias*ap1 && an2 > bias*ap2)
1495 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1496 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1498 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1499 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1500 if(ap1 > bias*an1 && ap2 > bias*an2)
1502 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1503 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1504 if(an1 > bias*ap1 && an2 > bias*ap2)
1506 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1507 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1509 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1510 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1511 if(ap1 > bias*an1 && ap2 > bias*an2)
1513 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1514 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1515 if(an1 > bias*ap1 && an2 > bias*ap2)
1517 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1518 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1523 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1525 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1527 // p is in the cubemap's local coordinate system
1528 // bias = border/(size - border)
1529 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1530 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1531 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1533 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1534 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1535 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1536 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1537 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1538 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1542 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1546 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1547 float scale = (size - 2*border)/size, len;
1548 float bias = border / (float)(size - border), dp, dn, ap, an;
1549 // check if cone enclosing side would cross frustum plane
1550 scale = 2 / (scale*scale + 2);
1551 Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
1552 for (i = 0;i < 5;i++)
1554 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
1556 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1557 len = scale*VectorLength2(n);
1558 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1559 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1560 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1562 if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1564 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1565 len = scale*VectorLength2(n);
1566 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1567 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1568 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1570 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1571 // check if frustum corners/origin cross plane sides
1573 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1574 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1575 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1576 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1577 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1578 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1579 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1580 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1581 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1582 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1583 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1584 for (i = 0;i < 4;i++)
1586 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1587 VectorSubtract(n, p, n);
1588 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1589 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1590 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1591 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1592 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1593 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1594 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1595 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1596 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1599 // finite version, assumes corners are a finite distance from origin dependent on far plane
1600 for (i = 0;i < 5;i++)
1602 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1603 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1604 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1605 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1606 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1607 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1608 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1609 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1610 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1611 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1614 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1617 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)
1625 int mask, surfacemask = 0;
1626 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1628 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1629 tend = firsttriangle + numtris;
1630 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1632 // surface box entirely inside light box, no box cull
1633 if (projectdirection)
1635 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1637 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1638 TriangleNormal(v[0], v[1], v[2], normal);
1639 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1641 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1642 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1643 surfacemask |= mask;
1646 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;
1647 shadowsides[numshadowsides] = mask;
1648 shadowsideslist[numshadowsides++] = t;
1655 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1657 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1658 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1660 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1661 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1662 surfacemask |= mask;
1665 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;
1666 shadowsides[numshadowsides] = mask;
1667 shadowsideslist[numshadowsides++] = t;
1675 // surface box not entirely inside light box, cull each triangle
1676 if (projectdirection)
1678 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1680 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1681 TriangleNormal(v[0], v[1], v[2], normal);
1682 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1683 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1685 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1686 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1687 surfacemask |= mask;
1690 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;
1691 shadowsides[numshadowsides] = mask;
1692 shadowsideslist[numshadowsides++] = t;
1699 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1701 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1702 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1703 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1705 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1706 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1707 surfacemask |= mask;
1710 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;
1711 shadowsides[numshadowsides] = mask;
1712 shadowsideslist[numshadowsides++] = t;
1721 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)
1723 int i, j, outtriangles = 0;
1724 int *outelement3i[6];
1725 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1727 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1728 // make sure shadowelements is big enough for this mesh
1729 if (maxshadowtriangles < outtriangles)
1730 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1732 // compute the offset and size of the separate index lists for each cubemap side
1734 for (i = 0;i < 6;i++)
1736 outelement3i[i] = shadowelements + outtriangles * 3;
1737 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1738 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1739 outtriangles += sidetotals[i];
1742 // gather up the (sparse) triangles into separate index lists for each cubemap side
1743 for (i = 0;i < numsidetris;i++)
1745 const int *element = elements + sidetris[i] * 3;
1746 for (j = 0;j < 6;j++)
1748 if (sides[i] & (1 << j))
1750 outelement3i[j][0] = element[0];
1751 outelement3i[j][1] = element[1];
1752 outelement3i[j][2] = element[2];
1753 outelement3i[j] += 3;
1758 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1761 static void R_Shadow_MakeTextures_MakeCorona(void)
1765 unsigned char pixels[32][32][4];
1766 for (y = 0;y < 32;y++)
1768 dy = (y - 15.5f) * (1.0f / 16.0f);
1769 for (x = 0;x < 32;x++)
1771 dx = (x - 15.5f) * (1.0f / 16.0f);
1772 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1773 a = bound(0, a, 255);
1774 pixels[y][x][0] = a;
1775 pixels[y][x][1] = a;
1776 pixels[y][x][2] = a;
1777 pixels[y][x][3] = 255;
1780 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, false);
1783 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1785 float dist = sqrt(x*x+y*y+z*z);
1786 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1787 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1788 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1791 static void R_Shadow_MakeTextures(void)
1794 float intensity, dist;
1796 R_Shadow_FreeShadowMaps();
1797 R_FreeTexturePool(&r_shadow_texturepool);
1798 r_shadow_texturepool = R_AllocTexturePool();
1799 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1800 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1801 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1802 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1803 for (x = 0;x <= ATTENTABLESIZE;x++)
1805 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1806 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1807 r_shadow_attentable[x] = bound(0, intensity, 1);
1809 // 1D gradient texture
1810 for (x = 0;x < ATTEN1DSIZE;x++)
1811 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1812 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1813 // 2D circle texture
1814 for (y = 0;y < ATTEN2DSIZE;y++)
1815 for (x = 0;x < ATTEN2DSIZE;x++)
1816 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);
1817 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1818 // 3D sphere texture
1819 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1821 for (z = 0;z < ATTEN3DSIZE;z++)
1822 for (y = 0;y < ATTEN3DSIZE;y++)
1823 for (x = 0;x < ATTEN3DSIZE;x++)
1824 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));
1825 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);
1828 r_shadow_attenuation3dtexture = NULL;
1831 R_Shadow_MakeTextures_MakeCorona();
1833 // Editor light sprites
1834 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1851 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1852 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1869 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1870 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1887 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1888 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1905 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1906 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1923 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1924 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1941 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1944 void R_Shadow_ValidateCvars(void)
1946 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1947 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1948 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1949 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1950 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1951 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1954 void R_Shadow_RenderMode_Begin(void)
1960 R_Shadow_ValidateCvars();
1962 if (!r_shadow_attenuation2dtexture
1963 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1964 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1965 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1966 R_Shadow_MakeTextures();
1969 R_Mesh_ResetTextureState();
1970 GL_BlendFunc(GL_ONE, GL_ZERO);
1971 GL_DepthRange(0, 1);
1972 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1974 GL_DepthMask(false);
1975 GL_Color(0, 0, 0, 1);
1976 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1978 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1980 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1982 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1983 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1985 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1987 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1988 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1992 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1993 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1996 switch(vid.renderpath)
1998 case RENDERPATH_GL20:
1999 case RENDERPATH_D3D9:
2000 case RENDERPATH_D3D10:
2001 case RENDERPATH_D3D11:
2002 case RENDERPATH_SOFT:
2003 case RENDERPATH_GLES2:
2004 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
2006 case RENDERPATH_GL11:
2007 case RENDERPATH_GL13:
2008 case RENDERPATH_GLES1:
2009 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
2010 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
2011 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
2012 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
2013 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
2014 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
2016 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
2022 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
2023 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
2024 r_shadow_drawbuffer = drawbuffer;
2025 r_shadow_readbuffer = readbuffer;
2027 r_shadow_cullface_front = r_refdef.view.cullface_front;
2028 r_shadow_cullface_back = r_refdef.view.cullface_back;
2031 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
2033 rsurface.rtlight = rtlight;
2036 void R_Shadow_RenderMode_Reset(void)
2038 R_Mesh_ResetTextureState();
2039 R_Mesh_SetRenderTargets(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture, NULL, NULL, NULL);
2040 R_SetViewport(&r_refdef.view.viewport);
2041 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
2042 GL_DepthRange(0, 1);
2044 GL_DepthMask(false);
2045 GL_DepthFunc(GL_LEQUAL);
2046 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2047 r_refdef.view.cullface_front = r_shadow_cullface_front;
2048 r_refdef.view.cullface_back = r_shadow_cullface_back;
2049 GL_CullFace(r_refdef.view.cullface_back);
2050 GL_Color(1, 1, 1, 1);
2051 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2052 GL_BlendFunc(GL_ONE, GL_ZERO);
2053 R_SetupShader_Generic_NoTexture(false, false);
2054 r_shadow_usingshadowmap2d = false;
2055 r_shadow_usingshadowmaportho = false;
2056 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2059 void R_Shadow_ClearStencil(void)
2061 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2062 r_refdef.stats[r_stat_lights_clears]++;
2065 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2067 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2068 if (r_shadow_rendermode == mode)
2070 R_Shadow_RenderMode_Reset();
2071 GL_DepthFunc(GL_LESS);
2072 GL_ColorMask(0, 0, 0, 0);
2073 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2074 GL_CullFace(GL_NONE);
2075 R_SetupShader_DepthOrShadow(false, false, false); // FIXME test if we have a skeletal model?
2076 r_shadow_rendermode = mode;
2081 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2082 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2083 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2085 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2086 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2087 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2092 static void R_Shadow_MakeVSDCT(void)
2094 // maps to a 2x3 texture rectangle with normalized coordinates
2099 // stores abs(dir.xy), offset.xy/2.5
2100 unsigned char data[4*6] =
2102 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2103 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2104 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2105 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2106 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2107 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2109 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2112 static void R_Shadow_MakeShadowMap(int side, int size)
2114 switch (r_shadow_shadowmode)
2116 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2117 if (r_shadow_shadowmap2ddepthtexture) return;
2118 if (r_fb.usedepthtextures)
2120 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);
2121 r_shadow_shadowmap2ddepthbuffer = NULL;
2122 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2126 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);
2127 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);
2128 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2136 static void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2138 float nearclip, farclip, bias;
2139 r_viewport_t viewport;
2142 float clearcolor[4];
2143 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2145 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2146 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2147 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2148 r_shadow_shadowmapside = side;
2149 r_shadow_shadowmapsize = size;
2151 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2152 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2153 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2154 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2156 // complex unrolled cube approach (more flexible)
2157 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2158 R_Shadow_MakeVSDCT();
2159 if (!r_shadow_shadowmap2ddepthtexture)
2160 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2161 fbo2d = r_shadow_fbo2d;
2162 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
2163 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
2164 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2166 R_Mesh_ResetTextureState();
2167 R_Shadow_RenderMode_Reset();
2168 if (r_shadow_shadowmap2ddepthbuffer)
2169 R_Mesh_SetRenderTargets(fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2171 R_Mesh_SetRenderTargets(fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2172 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2173 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2178 R_SetViewport(&viewport);
2179 flipped = (side & 1) ^ (side >> 2);
2180 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2181 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2182 if (r_shadow_shadowmap2ddepthbuffer)
2184 // completely different meaning than in depthtexture approach
2185 r_shadow_shadowmap_parameters[1] = 0;
2186 r_shadow_shadowmap_parameters[3] = -bias;
2188 Vector4Set(clearcolor, 1,1,1,1);
2189 if (r_shadow_shadowmap2ddepthbuffer)
2190 GL_ColorMask(1,1,1,1);
2192 GL_ColorMask(0,0,0,0);
2193 switch(vid.renderpath)
2195 case RENDERPATH_GL11:
2196 case RENDERPATH_GL13:
2197 case RENDERPATH_GL20:
2198 case RENDERPATH_SOFT:
2199 case RENDERPATH_GLES1:
2200 case RENDERPATH_GLES2:
2201 GL_CullFace(r_refdef.view.cullface_back);
2202 // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
2203 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2205 // get tightest scissor rectangle that encloses all viewports in the clear mask
2206 int x1 = clear & 0x15 ? 0 : size;
2207 int x2 = clear & 0x2A ? 2 * size : size;
2208 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2209 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2210 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2213 if (r_shadow_shadowmap2ddepthbuffer)
2214 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2216 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2219 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2221 case RENDERPATH_D3D9:
2222 case RENDERPATH_D3D10:
2223 case RENDERPATH_D3D11:
2224 // we invert the cull mode because we flip the projection matrix
2225 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2226 GL_CullFace(r_refdef.view.cullface_front);
2227 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2228 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2231 if (r_shadow_shadowmap2ddepthbuffer)
2232 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2234 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2240 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2242 R_Mesh_ResetTextureState();
2245 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2246 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2247 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2248 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2250 R_Shadow_RenderMode_Reset();
2251 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2253 GL_DepthFunc(GL_EQUAL);
2254 // do global setup needed for the chosen lighting mode
2255 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2256 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2257 r_shadow_usingshadowmap2d = shadowmapping;
2258 r_shadow_rendermode = r_shadow_lightingrendermode;
2259 // only draw light where this geometry was already rendered AND the
2260 // stencil is 128 (values other than this mean shadow)
2262 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2264 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2267 static const unsigned short bboxelements[36] =
2277 static const float bboxpoints[8][3] =
2289 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2292 float vertex3f[8*3];
2293 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2294 // do global setup needed for the chosen lighting mode
2295 R_Shadow_RenderMode_Reset();
2296 r_shadow_rendermode = r_shadow_lightingrendermode;
2297 R_EntityMatrix(&identitymatrix);
2298 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2299 // only draw light where this geometry was already rendered AND the
2300 // stencil is 128 (values other than this mean shadow)
2301 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2302 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
2303 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2305 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
2307 r_shadow_usingshadowmap2d = shadowmapping;
2309 // render the lighting
2310 R_SetupShader_DeferredLight(rsurface.rtlight);
2311 for (i = 0;i < 8;i++)
2312 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2313 GL_ColorMask(1,1,1,1);
2314 GL_DepthMask(false);
2315 GL_DepthRange(0, 1);
2316 GL_PolygonOffset(0, 0);
2318 GL_DepthFunc(GL_GREATER);
2319 GL_CullFace(r_refdef.view.cullface_back);
2320 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
2321 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2324 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
2326 qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
2333 // see if there are really any lights to render...
2334 if (enable && r_shadow_bouncegrid_static.integer)
2337 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2338 for (lightindex = 0;lightindex < range;lightindex++)
2340 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2341 if (!light || !(light->flags & flag))
2343 rtlight = &light->rtlight;
2344 // when static, we skip styled lights because they tend to change...
2345 if (rtlight->style > 0)
2347 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
2348 if (!VectorLength2(lightcolor))
2358 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
2360 // prevent any garbage in alignment padded areas as we'll be using memcmp
2361 memset(settings, 0, sizeof(*settings));
2363 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
2364 settings->staticmode = r_shadow_bouncegrid_static.integer != 0;
2365 settings->bounceanglediffuse = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
2366 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;
2367 settings->dlightparticlemultiplier = r_shadow_bouncegrid_dlightparticlemultiplier.value;
2368 settings->hitmodels = r_shadow_bouncegrid_hitmodels.integer != 0;
2369 settings->includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
2370 settings->lightradiusscale = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_lightradiusscale.value);
2371 settings->maxbounce = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_maxbounce.integer);
2372 settings->particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
2373 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);
2374 settings->maxphotons = r_shadow_bouncegrid_static.integer ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_maxphotons.integer;
2375 settings->intensityperphoton = r_shadow_bouncegrid_static.integer ? r_shadow_bouncegrid_static_intensityperphoton.integer : r_shadow_bouncegrid_intensityperphoton.integer;
2376 settings->spacing[0] = r_shadow_bouncegrid_spacing.value;
2377 settings->spacing[1] = r_shadow_bouncegrid_spacing.value;
2378 settings->spacing[2] = r_shadow_bouncegrid_spacing.value;
2379 settings->stablerandom = r_shadow_bouncegrid_stablerandom.integer;
2381 // bound the values for sanity
2382 settings->maxphotons = bound(1, settings->maxphotons, 25000000);
2383 settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
2384 settings->maxbounce = bound(0, settings->maxbounce, 16);
2385 settings->spacing[0] = bound(1, settings->spacing[0], 512);
2386 settings->spacing[1] = bound(1, settings->spacing[1], 512);
2387 settings->spacing[2] = bound(1, settings->spacing[2], 512);
2390 static void R_Shadow_BounceGrid_UpdateSpacing(void)
2401 r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
2403 // get the spacing values
2404 spacing[0] = settings->spacing[0];
2405 spacing[1] = settings->spacing[1];
2406 spacing[2] = settings->spacing[2];
2407 ispacing[0] = 1.0f / spacing[0];
2408 ispacing[1] = 1.0f / spacing[1];
2409 ispacing[2] = 1.0f / spacing[2];
2411 // calculate texture size enclosing entire world bounds at the spacing
2412 if (r_refdef.scene.worldmodel)
2414 VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
2415 VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
2419 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
2420 VectorSet(maxs, 1048576.0f, 1048576.0f, 1048576.0f);
2422 VectorSubtract(maxs, mins, size);
2423 // now we can calculate the resolution we want
2424 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2425 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2426 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2427 // figure out the exact texture size (honoring power of 2 if required)
2428 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2429 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2430 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2431 if (vid.support.arb_texture_non_power_of_two)
2433 resolution[0] = c[0];
2434 resolution[1] = c[1];
2435 resolution[2] = c[2];
2439 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2440 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2441 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2443 size[0] = spacing[0] * resolution[0];
2444 size[1] = spacing[1] * resolution[1];
2445 size[2] = spacing[2] * resolution[2];
2447 // if dynamic we may or may not want to use the world bounds
2448 // if the dynamic size is smaller than the world bounds, use it instead
2449 if (!settings->staticmode && (r_shadow_bouncegrid_x.integer * r_shadow_bouncegrid_y.integer * r_shadow_bouncegrid_z.integer < resolution[0] * resolution[1] * resolution[2]))
2451 // we know the resolution we want
2452 c[0] = r_shadow_bouncegrid_x.integer;
2453 c[1] = r_shadow_bouncegrid_y.integer;
2454 c[2] = r_shadow_bouncegrid_z.integer;
2455 // now we can calculate the texture size (power of 2 if required)
2456 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2457 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2458 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2459 if (vid.support.arb_texture_non_power_of_two)
2461 resolution[0] = c[0];
2462 resolution[1] = c[1];
2463 resolution[2] = c[2];
2467 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2468 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2469 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2471 size[0] = spacing[0] * resolution[0];
2472 size[1] = spacing[1] * resolution[1];
2473 size[2] = spacing[2] * resolution[2];
2474 // center the rendering on the view
2475 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2476 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2477 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2480 // recalculate the maxs in case the resolution was not satisfactory
2481 VectorAdd(mins, size, maxs);
2483 // check if this changed the texture size
2484 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);
2485 r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
2486 VectorCopy(mins, r_shadow_bouncegrid_state.mins);
2487 VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
2488 VectorCopy(size, r_shadow_bouncegrid_state.size);
2489 VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
2490 VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
2491 VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
2493 // reallocate pixels for this update if needed...
2494 r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
2495 r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
2496 r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
2497 numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
2498 if (r_shadow_bouncegrid_state.numpixels != numpixels || !r_shadow_bouncegrid_state.pixels || !r_shadow_bouncegrid_state.highpixels)
2500 if (r_shadow_bouncegrid_state.texture)
2502 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2503 r_shadow_bouncegrid_state.texture = NULL;
2505 r_shadow_bouncegrid_state.pixels = (unsigned char *)Mem_Realloc(r_main_mempool, r_shadow_bouncegrid_state.pixels, numpixels * sizeof(unsigned char[4]));
2506 r_shadow_bouncegrid_state.highpixels = (float *)Mem_Realloc(r_main_mempool, r_shadow_bouncegrid_state.highpixels, numpixels * sizeof(float[4]));
2507 r_shadow_bouncegrid_state.numpixels = numpixels;
2510 // update the bouncegrid matrix to put it in the world properly
2511 memset(m, 0, sizeof(m));
2512 m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
2513 m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
2514 m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
2515 m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
2516 m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
2517 m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
2519 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
2522 #define MAXBOUNCEGRIDPARTICLESPERLIGHT 1048576
2524 // enumerate world rtlights and sum the overall amount of light in the world,
2525 // from that we can calculate a scaling factor to fairly distribute photons
2526 // to all the lights
2528 // this modifies rtlight->photoncolor and rtlight->photons
2529 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)
2531 float normalphotonscaling;
2532 float maxphotonscaling;
2533 float photoncount = 0.0f;
2534 float lightintensity;
2540 unsigned int lightindex;
2543 for (lightindex = 0;lightindex < range2;lightindex++)
2545 if (lightindex < range)
2547 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2550 rtlight = &light->rtlight;
2551 VectorClear(rtlight->photoncolor);
2552 rtlight->photons = 0;
2553 if (!(light->flags & flag))
2555 if (settings->staticmode)
2557 // when static, we skip styled lights because they tend to change...
2558 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2564 rtlight = r_refdef.scene.lights[lightindex - range];
2565 VectorClear(rtlight->photoncolor);
2566 rtlight->photons = 0;
2568 // draw only visible lights (major speedup)
2569 radius = rtlight->radius * settings->lightradiusscale;
2570 cullmins[0] = rtlight->shadoworigin[0] - radius;
2571 cullmins[1] = rtlight->shadoworigin[1] - radius;
2572 cullmins[2] = rtlight->shadoworigin[2] - radius;
2573 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2574 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2575 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2576 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2577 if (!settings->staticmode)
2579 if (R_CullBox(cullmins, cullmaxs))
2581 if (r_refdef.scene.worldmodel
2582 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2583 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2585 if (w * VectorLength2(rtlight->color) == 0.0f)
2588 // a light that does not emit any light before style is applied, can be
2589 // skipped entirely (it may just be a corona)
2590 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2592 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2593 VectorScale(rtlight->color, w, rtlight->photoncolor);
2594 // skip lights that will emit no photons
2595 if (!VectorLength2(rtlight->photoncolor))
2597 // shoot particles from this light
2598 // use a calculation for the number of particles that will not
2599 // vary with lightstyle, otherwise we get randomized particle
2600 // distribution, the seeded random is only consistent for a
2601 // consistent number of particles on this light...
2602 s = rtlight->radius;
2603 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2604 if (lightindex >= range)
2605 lightintensity *= settings->dlightparticlemultiplier;
2606 rtlight->photons = bound(0.0f, lightintensity * s * s, MAXBOUNCEGRIDPARTICLESPERLIGHT);
2607 photoncount += rtlight->photons;
2608 // if the lightstyle happens to be off right now, we can skip actually
2609 // firing the photons, but we did have to count them in the total.
2610 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2611 // rtlight->photons = 0;
2613 // the user provided an intensityperphoton value which we try to use
2614 // if that results in too many photons to shoot this frame, then we cap it
2615 // which causes photons to appear/disappear from frame to frame, so we don't
2616 // like doing that in the typical case
2617 normalphotonscaling = 1.0f / max(0.0001f, r_shadow_bouncegrid_intensityperphoton.value);
2618 maxphotonscaling = (float)settings->maxphotons / max(1, photoncount);
2619 *photonscaling = min(normalphotonscaling, maxphotonscaling);
2622 static void R_Shadow_BounceGrid_ClearPixels(void)
2625 for (pixelband = 0;pixelband < r_shadow_bouncegrid_state.pixelbands;pixelband++)
2628 memset(r_shadow_bouncegrid_state.pixels + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
2630 memset(r_shadow_bouncegrid_state.pixels + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
2632 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2635 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
2637 unsigned char *pixels = r_shadow_bouncegrid_state.pixels;
2638 unsigned char *pixel;
2639 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2641 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2642 unsigned int pixelband;
2643 unsigned int x, y, z;
2645 unsigned int resolution[3];
2647 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2648 // generate pixels array from highpixels array
2650 // skip first and last columns, rows, and layers as these are blank
2652 // the pixel[3] value was deliberately written along with highpixels
2653 // updates, so we can use it to detect only pixels that need to be
2654 // converted, the rest were already memset to neutral values.
2655 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2657 for (z = 1;z < resolution[2]-1;z++)
2659 for (y = 1;y < resolution[1]-1;y++)
2662 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2663 pixel = pixels + 4*index;
2664 highpixel = highpixels + 4*index;
2665 for (;x < resolution[0]-1;x++, pixel += 4, highpixel += 4)
2667 // only convert pixels that were hit by photons
2668 if (pixel[3] == 255)
2670 // normalize the bentnormal...
2673 VectorNormalize(highpixel);
2674 c[0] = (int)(highpixel[0]*128.0f+128.0f);
2675 c[1] = (int)(highpixel[1]*128.0f+128.0f);
2676 c[2] = (int)(highpixel[2]*128.0f+128.0f);
2677 c[3] = (int)(highpixel[3]*128.0f+128.0f);
2681 c[0] = (int)(highpixel[0]*256.0f);
2682 c[1] = (int)(highpixel[1]*256.0f);
2683 c[2] = (int)(highpixel[2]*256.0f);
2684 c[3] = (int)(highpixel[3]*256.0f);
2686 pixel[2] = (unsigned char)bound(0, c[0], 255);
2687 pixel[1] = (unsigned char)bound(0, c[1], 255);
2688 pixel[0] = (unsigned char)bound(0, c[2], 255);
2689 pixel[3] = (unsigned char)bound(0, c[3], 255);
2696 if (!r_shadow_bouncegrid_state.createtexture)
2697 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixels, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2700 if (r_shadow_bouncegrid_state.texture)
2701 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2702 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);
2704 r_shadow_bouncegrid_state.lastupdatetime = realtime;
2707 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)
2711 int hitsupercontentsmask;
2718 //trace_t cliptrace2;
2719 //trace_t cliptrace3;
2720 unsigned char *pixel;
2721 unsigned char *pixels = r_shadow_bouncegrid_state.pixels;
2723 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2724 unsigned int lightindex;
2725 unsigned int seed = (unsigned int)(realtime * 1000.0f);
2727 vec3_t baseshotcolor;
2736 float texlerp[2][3];
2737 float splatcolor[32];
2738 float pixelweight[8];
2742 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2744 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2748 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2750 // figure out what we want to interact with
2751 if (settings.hitmodels)
2752 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;// | SUPERCONTENTS_LIQUIDSMASK;
2754 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
2755 maxbounce = settings.maxbounce;
2756 // clear variables that produce warnings otherwise
2757 memset(splatcolor, 0, sizeof(splatcolor));
2759 for (lightindex = 0;lightindex < range2;lightindex++)
2761 if (lightindex < range)
2763 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2766 rtlight = &light->rtlight;
2769 rtlight = r_refdef.scene.lights[lightindex - range];
2770 // note that this code used to keep track of residual photons and
2771 // distribute them evenly to achieve exactly a desired photon count,
2772 // but that caused unwanted flickering in dynamic mode
2773 shootparticles = (int)floor(rtlight->photons * photonscaling);
2774 // skip if we won't be shooting any photons
2775 if (!shootparticles)
2777 radius = rtlight->radius * settings.lightradiusscale;
2778 s = settings.particleintensity / shootparticles;
2779 VectorScale(rtlight->photoncolor, s, baseshotcolor);
2780 r_refdef.stats[r_stat_bouncegrid_lights]++;
2781 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
2782 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2784 if (settings.stablerandom > 0)
2785 seed = lightindex * 11937 + shotparticles;
2786 VectorCopy(baseshotcolor, shotcolor);
2787 VectorCopy(rtlight->shadoworigin, clipstart);
2788 if (settings.stablerandom < 0)
2789 VectorRandom(clipend);
2791 VectorCheeseRandom(clipend);
2792 VectorMA(clipstart, radius, clipend, clipend);
2793 for (bouncecount = 0;;bouncecount++)
2795 r_refdef.stats[r_stat_bouncegrid_traces]++;
2796 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2797 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2798 if (settings.staticmode)
2800 // static mode fires a LOT of rays but none of them are identical, so they are not cached
2801 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);
2805 // dynamic mode fires many rays and most will match the cache from the previous frame
2806 cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask);
2808 if (bouncecount > 0 || settings.includedirectlighting)
2810 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2811 // accumulate average shotcolor
2812 w = VectorLength(shotcolor);
2813 splatcolor[ 0] = shotcolor[0];
2814 splatcolor[ 1] = shotcolor[1];
2815 splatcolor[ 2] = shotcolor[2];
2816 splatcolor[ 3] = 0.0f;
2819 VectorSubtract(clipstart, cliptrace.endpos, clipdiff);
2820 VectorNormalize(clipdiff);
2821 // store bentnormal in case the shader has a use for it
2822 splatcolor[ 4] = clipdiff[0] * w;
2823 splatcolor[ 5] = clipdiff[1] * w;
2824 splatcolor[ 6] = clipdiff[2] * w;
2826 // accumulate directional contributions (+X, +Y, +Z, -X, -Y, -Z)
2827 splatcolor[ 8] = shotcolor[0] * max(0.0f, clipdiff[0]);
2828 splatcolor[ 9] = shotcolor[0] * max(0.0f, clipdiff[1]);
2829 splatcolor[10] = shotcolor[0] * max(0.0f, clipdiff[2]);
2830 splatcolor[11] = 0.0f;
2831 splatcolor[12] = shotcolor[1] * max(0.0f, clipdiff[0]);
2832 splatcolor[13] = shotcolor[1] * max(0.0f, clipdiff[1]);
2833 splatcolor[14] = shotcolor[1] * max(0.0f, clipdiff[2]);
2834 splatcolor[15] = 0.0f;
2835 splatcolor[16] = shotcolor[2] * max(0.0f, clipdiff[0]);
2836 splatcolor[17] = shotcolor[2] * max(0.0f, clipdiff[1]);
2837 splatcolor[18] = shotcolor[2] * max(0.0f, clipdiff[2]);
2838 splatcolor[19] = 0.0f;
2839 splatcolor[20] = shotcolor[0] * max(0.0f, -clipdiff[0]);
2840 splatcolor[21] = shotcolor[0] * max(0.0f, -clipdiff[1]);
2841 splatcolor[22] = shotcolor[0] * max(0.0f, -clipdiff[2]);
2842 splatcolor[23] = 0.0f;
2843 splatcolor[24] = shotcolor[1] * max(0.0f, -clipdiff[0]);
2844 splatcolor[25] = shotcolor[1] * max(0.0f, -clipdiff[1]);
2845 splatcolor[26] = shotcolor[1] * max(0.0f, -clipdiff[2]);
2846 splatcolor[27] = 0.0f;
2847 splatcolor[28] = shotcolor[2] * max(0.0f, -clipdiff[0]);
2848 splatcolor[29] = shotcolor[2] * max(0.0f, -clipdiff[1]);
2849 splatcolor[30] = shotcolor[2] * max(0.0f, -clipdiff[2]);
2850 splatcolor[31] = 0.0f;
2852 // calculate the number of steps we need to traverse this distance
2853 VectorSubtract(cliptrace.endpos, clipstart, stepdelta);
2854 numsteps = (int)(VectorLength(stepdelta) * r_shadow_bouncegrid_state.ispacing[0]);
2855 numsteps = bound(1, numsteps, 1024);
2856 w = 1.0f / numsteps;
2857 VectorScale(stepdelta, w, stepdelta);
2858 VectorMA(clipstart, 0.5f, stepdelta, steppos);
2859 for (step = 0;step < numsteps;step++)
2861 r_refdef.stats[r_stat_bouncegrid_splats]++;
2862 // figure out which texture pixel this is in
2863 texlerp[1][0] = ((steppos[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0]) - 0.5f;
2864 texlerp[1][1] = ((steppos[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1]) - 0.5f;
2865 texlerp[1][2] = ((steppos[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2]) - 0.5f;
2866 tex[0] = (int)floor(texlerp[1][0]);
2867 tex[1] = (int)floor(texlerp[1][1]);
2868 tex[2] = (int)floor(texlerp[1][2]);
2869 if (tex[0] >= 1 && tex[1] >= 1 && tex[2] >= 1 && tex[0] < resolution[0] - 2 && tex[1] < resolution[1] - 2 && tex[2] < resolution[2] - 2)
2871 // it is within bounds... do the real work now
2872 // calculate the lerp factors
2873 texlerp[1][0] -= tex[0];
2874 texlerp[1][1] -= tex[1];
2875 texlerp[1][2] -= tex[2];
2876 texlerp[0][0] = 1.0f - texlerp[1][0];
2877 texlerp[0][1] = 1.0f - texlerp[1][1];
2878 texlerp[0][2] = 1.0f - texlerp[1][2];
2879 // calculate individual pixel indexes and weights
2880 pixelindex[0] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[0] = (texlerp[0][0]*texlerp[0][1]*texlerp[0][2]);
2881 pixelindex[1] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0]+1);pixelweight[1] = (texlerp[1][0]*texlerp[0][1]*texlerp[0][2]);
2882 pixelindex[2] = (((tex[2] )*resolution[1]+tex[1]+1)*resolution[0]+tex[0] );pixelweight[2] = (texlerp[0][0]*texlerp[1][1]*texlerp[0][2]);
2883 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]);
2884 pixelindex[4] = (((tex[2]+1)*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[4] = (texlerp[0][0]*texlerp[0][1]*texlerp[1][2]);
2885 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]);
2886 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]);
2887 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]);
2888 // update the 8 pixels...
2889 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2891 for (corner = 0;corner < 8;corner++)
2893 // calculate address for pixel
2894 w = pixelweight[corner];
2895 pixel = pixels + 4 * pixelindex[corner] + pixelband * pixelsperband * 4;
2896 highpixel = highpixels + 4 * pixelindex[corner] + pixelband * pixelsperband * 4;
2897 // add to the high precision pixel color
2898 highpixel[0] += (splatcolor[pixelband*4+0]*w);
2899 highpixel[1] += (splatcolor[pixelband*4+1]*w);
2900 highpixel[2] += (splatcolor[pixelband*4+2]*w);
2901 highpixel[3] += (splatcolor[pixelband*4+3]*w);
2902 // flag the low precision pixel as needing to be updated
2904 // advance to next band of coefficients
2905 //pixel += pixelsperband*4;
2906 //highpixel += pixelsperband*4;
2910 VectorAdd(steppos, stepdelta, steppos);
2913 if (cliptrace.fraction >= 1.0f)
2915 r_refdef.stats[r_stat_bouncegrid_hits]++;
2916 if (bouncecount >= maxbounce)
2918 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2919 // also clamp the resulting color to never add energy, even if the user requests extreme values
2920 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2921 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
2923 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
2924 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
2925 surfcolor[0] = min(surfcolor[0], 1.0f);
2926 surfcolor[1] = min(surfcolor[1], 1.0f);
2927 surfcolor[2] = min(surfcolor[2], 1.0f);
2928 VectorMultiply(shotcolor, surfcolor, shotcolor);
2929 if (VectorLength2(baseshotcolor) == 0.0f)
2931 r_refdef.stats[r_stat_bouncegrid_bounces]++;
2932 if (settings.bounceanglediffuse)
2934 // random direction, primarily along plane normal
2935 s = VectorDistance(cliptrace.endpos, clipend);
2936 if (settings.stablerandom < 0)
2937 VectorRandom(clipend);
2939 VectorCheeseRandom(clipend);
2940 VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
2941 VectorNormalize(clipend);
2942 VectorScale(clipend, s, clipend);
2946 // reflect the remaining portion of the line across plane normal
2947 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2948 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2950 // calculate the new line start and end
2951 VectorCopy(cliptrace.endpos, clipstart);
2952 VectorAdd(clipstart, clipend, clipend);
2958 void R_Shadow_UpdateBounceGridTexture(void)
2960 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2961 r_shadow_bouncegrid_settings_t settings;
2962 qboolean enable = false;
2963 qboolean settingschanged;
2964 unsigned int range; // number of world lights
2965 unsigned int range1; // number of dynamic lights (or zero if disabled)
2966 unsigned int range2; // range+range1
2967 float photonscaling;
2969 enable = R_Shadow_BounceGrid_CheckEnable(flag);
2971 R_Shadow_BounceGrid_GenerateSettings(&settings);
2973 // changing intensity does not require an update
2974 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
2976 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
2978 // when settings change, we free everything as it is just simpler that way.
2979 if (settingschanged || !enable)
2981 // not enabled, make sure we free anything we don't need anymore.
2982 if (r_shadow_bouncegrid_state.texture)
2984 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2985 r_shadow_bouncegrid_state.texture = NULL;
2987 if (r_shadow_bouncegrid_state.pixels)
2988 Mem_Free(r_shadow_bouncegrid_state.pixels);
2989 r_shadow_bouncegrid_state.pixels = NULL;
2990 if (r_shadow_bouncegrid_state.highpixels)
2991 Mem_Free(r_shadow_bouncegrid_state.highpixels);
2992 r_shadow_bouncegrid_state.highpixels = NULL;
2993 r_shadow_bouncegrid_state.numpixels = 0;
2994 r_shadow_bouncegrid_state.directional = false;
3000 // if all the settings seem identical to the previous update, return
3001 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_updateinterval.value) && !settingschanged)
3004 // store the new settings
3005 r_shadow_bouncegrid_state.settings = settings;
3007 R_Shadow_BounceGrid_UpdateSpacing();
3009 // get the range of light numbers we'll be looping over:
3010 // range = static lights
3011 // range1 = dynamic lights (optional)
3012 // range2 = range + range1
3013 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3014 range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
3015 range2 = range + range1;
3017 // calculate weighting factors for distributing photons among the lights
3018 R_Shadow_BounceGrid_AssignPhotons(&settings, range, range1, range2, flag, &photonscaling);
3020 // clear the pixels[] and highpixels[] arrays, it is important that we
3021 // clear pixels[] now because we do tricks with marking pixels as needing
3022 // conversion, even though the source of truth data is in highpixels[]
3023 R_Shadow_BounceGrid_ClearPixels();
3025 // trace the photons from lights and accumulate illumination
3026 R_Shadow_BounceGrid_TracePhotons(settings, range, range1, range2, photonscaling, flag);
3028 // convert the pixels that were marked and upload the texture
3029 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
3032 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
3034 R_Shadow_RenderMode_Reset();
3035 GL_BlendFunc(GL_ONE, GL_ONE);
3036 GL_DepthRange(0, 1);
3037 GL_DepthTest(r_showshadowvolumes.integer < 2);
3038 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
3039 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
3040 GL_CullFace(GL_NONE);
3041 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
3044 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
3046 R_Shadow_RenderMode_Reset();
3047 GL_BlendFunc(GL_ONE, GL_ONE);
3048 GL_DepthRange(0, 1);
3049 GL_DepthTest(r_showlighting.integer < 2);
3050 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
3052 GL_DepthFunc(GL_EQUAL);
3053 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
3054 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
3057 void R_Shadow_RenderMode_End(void)
3059 R_Shadow_RenderMode_Reset();
3060 R_Shadow_RenderMode_ActiveLight(NULL);
3062 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3063 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3066 int bboxedges[12][2] =
3085 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
3087 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
3089 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
3090 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
3091 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
3092 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
3095 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
3096 return true; // invisible
3097 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
3098 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
3099 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
3100 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
3101 r_refdef.stats[r_stat_lights_scissored]++;
3105 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
3108 const float *vertex3f;
3109 const float *normal3f;
3111 float dist, dot, distintensity, shadeintensity, v[3], n[3];
3112 switch (r_shadow_rendermode)
3114 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3115 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3116 if (VectorLength2(diffusecolor) > 0)
3118 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)
3120 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3121 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3122 if ((dot = DotProduct(n, v)) < 0)
3124 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3125 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
3128 VectorCopy(ambientcolor, color4f);
3129 if (r_refdef.fogenabled)
3132 f = RSurf_FogVertex(vertex3f);
3133 VectorScale(color4f, f, color4f);
3140 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3142 VectorCopy(ambientcolor, color4f);
3143 if (r_refdef.fogenabled)
3146 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3147 f = RSurf_FogVertex(vertex3f);
3148 VectorScale(color4f + 4*i, f, color4f);
3154 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3155 if (VectorLength2(diffusecolor) > 0)
3157 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)
3159 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3160 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3162 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3163 if ((dot = DotProduct(n, v)) < 0)
3165 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3166 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3167 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3168 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3172 color4f[0] = ambientcolor[0] * distintensity;
3173 color4f[1] = ambientcolor[1] * distintensity;
3174 color4f[2] = ambientcolor[2] * distintensity;
3176 if (r_refdef.fogenabled)
3179 f = RSurf_FogVertex(vertex3f);
3180 VectorScale(color4f, f, color4f);
3184 VectorClear(color4f);
3190 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3192 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3193 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3195 color4f[0] = ambientcolor[0] * distintensity;
3196 color4f[1] = ambientcolor[1] * distintensity;
3197 color4f[2] = ambientcolor[2] * distintensity;
3198 if (r_refdef.fogenabled)
3201 f = RSurf_FogVertex(vertex3f);
3202 VectorScale(color4f, f, color4f);
3206 VectorClear(color4f);
3211 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3212 if (VectorLength2(diffusecolor) > 0)
3214 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)
3216 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3217 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3219 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3220 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3221 if ((dot = DotProduct(n, v)) < 0)
3223 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3224 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3225 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3226 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3230 color4f[0] = ambientcolor[0] * distintensity;
3231 color4f[1] = ambientcolor[1] * distintensity;
3232 color4f[2] = ambientcolor[2] * distintensity;
3234 if (r_refdef.fogenabled)
3237 f = RSurf_FogVertex(vertex3f);
3238 VectorScale(color4f, f, color4f);
3242 VectorClear(color4f);
3248 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3250 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3251 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3253 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3254 color4f[0] = ambientcolor[0] * distintensity;
3255 color4f[1] = ambientcolor[1] * distintensity;
3256 color4f[2] = ambientcolor[2] * distintensity;
3257 if (r_refdef.fogenabled)
3260 f = RSurf_FogVertex(vertex3f);
3261 VectorScale(color4f, f, color4f);
3265 VectorClear(color4f);
3275 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3277 // used to display how many times a surface is lit for level design purposes
3278 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3279 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3283 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
3285 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3286 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
3290 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3297 int newnumtriangles;
3301 int maxtriangles = 1024;
3302 int newelements[1024*3];
3303 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3304 for (renders = 0;renders < 4;renders++)
3309 newnumtriangles = 0;
3311 // due to low fillrate on the cards this vertex lighting path is
3312 // designed for, we manually cull all triangles that do not
3313 // contain a lit vertex
3314 // this builds batches of triangles from multiple surfaces and
3315 // renders them at once
3316 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3318 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3320 if (newnumtriangles)
3322 newfirstvertex = min(newfirstvertex, e[0]);
3323 newlastvertex = max(newlastvertex, e[0]);
3327 newfirstvertex = e[0];
3328 newlastvertex = e[0];
3330 newfirstvertex = min(newfirstvertex, e[1]);
3331 newlastvertex = max(newlastvertex, e[1]);
3332 newfirstvertex = min(newfirstvertex, e[2]);
3333 newlastvertex = max(newlastvertex, e[2]);
3339 if (newnumtriangles >= maxtriangles)
3341 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3342 newnumtriangles = 0;
3348 if (newnumtriangles >= 1)
3350 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3353 // if we couldn't find any lit triangles, exit early
3356 // now reduce the intensity for the next overbright pass
3357 // we have to clamp to 0 here incase the drivers have improper
3358 // handling of negative colors
3359 // (some old drivers even have improper handling of >1 color)
3361 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3363 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3365 c[0] = max(0, c[0] - 1);
3366 c[1] = max(0, c[1] - 1);
3367 c[2] = max(0, c[2] - 1);
3379 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
3381 // OpenGL 1.1 path (anything)
3382 float ambientcolorbase[3], diffusecolorbase[3];
3383 float ambientcolorpants[3], diffusecolorpants[3];
3384 float ambientcolorshirt[3], diffusecolorshirt[3];
3385 const float *surfacecolor = rsurface.texture->dlightcolor;
3386 const float *surfacepants = rsurface.colormap_pantscolor;
3387 const float *surfaceshirt = rsurface.colormap_shirtcolor;
3388 rtexture_t *basetexture = rsurface.texture->basetexture;
3389 rtexture_t *pantstexture = rsurface.texture->pantstexture;
3390 rtexture_t *shirttexture = rsurface.texture->shirttexture;
3391 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3392 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3393 ambientscale *= 2 * r_refdef.view.colorscale;
3394 diffusescale *= 2 * r_refdef.view.colorscale;
3395 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3396 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3397 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3398 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3399 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3400 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
3401 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3402 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
3403 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3404 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
3405 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
3406 R_Mesh_TexBind(0, basetexture);
3407 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
3408 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
3409 switch(r_shadow_rendermode)
3411 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3412 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
3413 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3414 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3415 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3417 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3418 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
3419 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
3420 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
3421 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3423 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3424 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
3425 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3426 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3427 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3429 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3434 //R_Mesh_TexBind(0, basetexture);
3435 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
3438 R_Mesh_TexBind(0, pantstexture);
3439 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
3443 R_Mesh_TexBind(0, shirttexture);
3444 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
3448 extern cvar_t gl_lightmaps;
3449 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3451 float ambientscale, diffusescale, specularscale;
3453 float lightcolor[3];
3454 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
3455 ambientscale = rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient;
3456 diffusescale = rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient);
3457 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3458 if (!r_shadow_usenormalmap.integer)
3460 ambientscale += 1.0f * diffusescale;
3464 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
3466 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
3469 VectorNegate(lightcolor, lightcolor);
3470 GL_BlendEquationSubtract(true);
3472 RSurf_SetupDepthAndCulling();
3473 switch (r_shadow_rendermode)
3475 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3476 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3477 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
3479 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3480 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
3482 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3483 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3484 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3485 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3486 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
3489 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3493 GL_BlendEquationSubtract(false);
3496 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)
3498 matrix4x4_t tempmatrix = *matrix;
3499 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3501 // if this light has been compiled before, free the associated data
3502 R_RTLight_Uncompile(rtlight);
3504 // clear it completely to avoid any lingering data
3505 memset(rtlight, 0, sizeof(*rtlight));
3507 // copy the properties
3508 rtlight->matrix_lighttoworld = tempmatrix;
3509 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3510 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3511 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3512 VectorCopy(color, rtlight->color);
3513 rtlight->cubemapname[0] = 0;
3514 if (cubemapname && cubemapname[0])
3515 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3516 rtlight->shadow = shadow;
3517 rtlight->corona = corona;
3518 rtlight->style = style;
3519 rtlight->isstatic = isstatic;
3520 rtlight->coronasizescale = coronasizescale;
3521 rtlight->ambientscale = ambientscale;
3522 rtlight->diffusescale = diffusescale;
3523 rtlight->specularscale = specularscale;
3524 rtlight->flags = flags;
3526 // compute derived data
3527 //rtlight->cullradius = rtlight->radius;
3528 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3529 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3530 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3531 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3532 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3533 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3534 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3537 // compiles rtlight geometry
3538 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3539 void R_RTLight_Compile(rtlight_t *rtlight)
3542 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3543 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3544 entity_render_t *ent = r_refdef.scene.worldentity;
3545 dp_model_t *model = r_refdef.scene.worldmodel;
3546 unsigned char *data;
3549 // compile the light
3550 rtlight->compiled = true;
3551 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3552 rtlight->static_numleafs = 0;
3553 rtlight->static_numleafpvsbytes = 0;
3554 rtlight->static_leaflist = NULL;
3555 rtlight->static_leafpvs = NULL;
3556 rtlight->static_numsurfaces = 0;
3557 rtlight->static_surfacelist = NULL;
3558 rtlight->static_shadowmap_receivers = 0x3F;
3559 rtlight->static_shadowmap_casters = 0x3F;
3560 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3561 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3562 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3563 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3564 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3565 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3567 if (model && model->GetLightInfo)
3569 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3570 r_shadow_compilingrtlight = rtlight;
3571 R_FrameData_SetMark();
3572 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);
3573 R_FrameData_ReturnToMark();
3574 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3575 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3576 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3577 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3578 rtlight->static_numsurfaces = numsurfaces;
3579 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3580 rtlight->static_numleafs = numleafs;
3581 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3582 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3583 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3584 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3585 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3586 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3587 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3588 if (rtlight->static_numsurfaces)
3589 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3590 if (rtlight->static_numleafs)
3591 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3592 if (rtlight->static_numleafpvsbytes)
3593 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3594 if (rtlight->static_numshadowtrispvsbytes)
3595 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3596 if (rtlight->static_numlighttrispvsbytes)
3597 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3598 R_FrameData_SetMark();
3599 switch (rtlight->shadowmode)
3601 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3602 if (model->CompileShadowMap && rtlight->shadow)
3603 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3606 if (model->CompileShadowVolume && rtlight->shadow)
3607 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3610 R_FrameData_ReturnToMark();
3611 // now we're done compiling the rtlight
3612 r_shadow_compilingrtlight = NULL;
3616 // use smallest available cullradius - box radius or light radius
3617 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3618 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3620 shadowzpasstris = 0;
3621 if (rtlight->static_meshchain_shadow_zpass)
3622 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3623 shadowzpasstris += mesh->numtriangles;
3625 shadowzfailtris = 0;
3626 if (rtlight->static_meshchain_shadow_zfail)
3627 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3628 shadowzfailtris += mesh->numtriangles;
3631 if (rtlight->static_numlighttrispvsbytes)
3632 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3633 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3637 if (rtlight->static_numshadowtrispvsbytes)
3638 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3639 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3642 if (developer_extra.integer)
3643 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);
3646 void R_RTLight_Uncompile(rtlight_t *rtlight)
3648 if (rtlight->compiled)
3650 if (rtlight->static_meshchain_shadow_zpass)
3651 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3652 rtlight->static_meshchain_shadow_zpass = NULL;
3653 if (rtlight->static_meshchain_shadow_zfail)
3654 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3655 rtlight->static_meshchain_shadow_zfail = NULL;
3656 if (rtlight->static_meshchain_shadow_shadowmap)
3657 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3658 rtlight->static_meshchain_shadow_shadowmap = NULL;
3659 // these allocations are grouped
3660 if (rtlight->static_surfacelist)
3661 Mem_Free(rtlight->static_surfacelist);
3662 rtlight->static_numleafs = 0;
3663 rtlight->static_numleafpvsbytes = 0;
3664 rtlight->static_leaflist = NULL;
3665 rtlight->static_leafpvs = NULL;
3666 rtlight->static_numsurfaces = 0;
3667 rtlight->static_surfacelist = NULL;
3668 rtlight->static_numshadowtrispvsbytes = 0;
3669 rtlight->static_shadowtrispvs = NULL;
3670 rtlight->static_numlighttrispvsbytes = 0;
3671 rtlight->static_lighttrispvs = NULL;
3672 rtlight->compiled = false;
3676 void R_Shadow_UncompileWorldLights(void)
3680 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3681 for (lightindex = 0;lightindex < range;lightindex++)
3683 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3686 R_RTLight_Uncompile(&light->rtlight);
3690 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3694 // reset the count of frustum planes
3695 // see rtlight->cached_frustumplanes definition for how much this array
3697 rtlight->cached_numfrustumplanes = 0;
3699 if (r_trippy.integer)
3702 // haven't implemented a culling path for ortho rendering
3703 if (!r_refdef.view.useperspective)
3705 // check if the light is on screen and copy the 4 planes if it is
3706 for (i = 0;i < 4;i++)
3707 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3710 for (i = 0;i < 4;i++)
3711 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3716 // generate a deformed frustum that includes the light origin, this is
3717 // used to cull shadow casting surfaces that can not possibly cast a
3718 // shadow onto the visible light-receiving surfaces, which can be a
3721 // if the light origin is onscreen the result will be 4 planes exactly
3722 // if the light origin is offscreen on only one axis the result will
3723 // be exactly 5 planes (split-side case)
3724 // if the light origin is offscreen on two axes the result will be
3725 // exactly 4 planes (stretched corner case)
3726 for (i = 0;i < 4;i++)
3728 // quickly reject standard frustum planes that put the light
3729 // origin outside the frustum
3730 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3733 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3735 // if all the standard frustum planes were accepted, the light is onscreen
3736 // otherwise we need to generate some more planes below...
3737 if (rtlight->cached_numfrustumplanes < 4)
3739 // at least one of the stock frustum planes failed, so we need to
3740 // create one or two custom planes to enclose the light origin
3741 for (i = 0;i < 4;i++)
3743 // create a plane using the view origin and light origin, and a
3744 // single point from the frustum corner set
3745 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3746 VectorNormalize(plane.normal);
3747 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3748 // see if this plane is backwards and flip it if so
3749 for (j = 0;j < 4;j++)
3750 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3754 VectorNegate(plane.normal, plane.normal);
3756 // flipped plane, test again to see if it is now valid
3757 for (j = 0;j < 4;j++)
3758 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3760 // if the plane is still not valid, then it is dividing the
3761 // frustum and has to be rejected
3765 // we have created a valid plane, compute extra info
3766 PlaneClassify(&plane);
3768 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3770 // if we've found 5 frustum planes then we have constructed a
3771 // proper split-side case and do not need to keep searching for
3772 // planes to enclose the light origin
3773 if (rtlight->cached_numfrustumplanes == 5)
3781 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3783 plane = rtlight->cached_frustumplanes[i];
3784 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));
3789 // now add the light-space box planes if the light box is rotated, as any
3790 // caster outside the oriented light box is irrelevant (even if it passed
3791 // the worldspace light box, which is axial)
3792 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3794 for (i = 0;i < 6;i++)
3798 v[i >> 1] = (i & 1) ? -1 : 1;
3799 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3800 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3801 plane.dist = VectorNormalizeLength(plane.normal);
3802 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3803 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3809 // add the world-space reduced box planes
3810 for (i = 0;i < 6;i++)
3812 VectorClear(plane.normal);
3813 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3814 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3815 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3824 // reduce all plane distances to tightly fit the rtlight cull box, which
3826 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3827 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3828 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3829 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3830 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3831 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3832 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3833 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3834 oldnum = rtlight->cached_numfrustumplanes;
3835 rtlight->cached_numfrustumplanes = 0;
3836 for (j = 0;j < oldnum;j++)
3838 // find the nearest point on the box to this plane
3839 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3840 for (i = 1;i < 8;i++)
3842 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3843 if (bestdist > dist)
3846 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);
3847 // if the nearest point is near or behind the plane, we want this
3848 // plane, otherwise the plane is useless as it won't cull anything
3849 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3851 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3852 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3859 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3863 RSurf_ActiveWorldEntity();
3865 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3868 GL_CullFace(GL_NONE);
3869 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3870 for (;mesh;mesh = mesh->next)
3872 if (!mesh->sidetotals[r_shadow_shadowmapside])
3874 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
3875 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
3876 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);
3880 else if (r_refdef.scene.worldentity->model)
3881 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);
3883 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3886 static void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3888 qboolean zpass = false;
3891 int surfacelistindex;
3892 msurface_t *surface;
3894 // if triangle neighbors are disabled, shadowvolumes are disabled
3895 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
3898 RSurf_ActiveWorldEntity();
3900 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3903 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3905 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3906 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3908 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3909 for (;mesh;mesh = mesh->next)
3911 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->numtriangles;
3912 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
3913 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3915 // increment stencil if frontface is infront of depthbuffer
3916 GL_CullFace(r_refdef.view.cullface_back);
3917 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3918 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);
3919 // decrement stencil if backface is infront of depthbuffer
3920 GL_CullFace(r_refdef.view.cullface_front);
3921 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3923 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3925 // decrement stencil if backface is behind depthbuffer
3926 GL_CullFace(r_refdef.view.cullface_front);
3927 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3928 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);
3929 // increment stencil if frontface is behind depthbuffer
3930 GL_CullFace(r_refdef.view.cullface_back);
3931 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3933 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);
3937 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3939 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3940 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3941 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3943 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3944 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3945 if (CHECKPVSBIT(trispvs, t))
3946 shadowmarklist[numshadowmark++] = t;
3948 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);
3950 else if (numsurfaces)
3952 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);
3955 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3958 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3960 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3961 vec_t relativeshadowradius;
3962 RSurf_ActiveModelEntity(ent, false, false, false);
3963 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3964 // we need to re-init the shader for each entity because the matrix changed
3965 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3966 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3967 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3968 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3969 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3970 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3971 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3972 switch (r_shadow_rendermode)
3974 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3975 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3978 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3981 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3984 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3986 // set up properties for rendering light onto this entity
3987 RSurf_ActiveModelEntity(ent, true, true, false);
3988 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3989 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3990 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3991 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3994 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3996 if (!r_refdef.scene.worldmodel->DrawLight)
3999 // set up properties for rendering light onto this entity
4000 RSurf_ActiveWorldEntity();
4001 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
4002 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4003 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4004 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4006 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
4008 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4011 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
4013 dp_model_t *model = ent->model;
4014 if (!model->DrawLight)
4017 R_Shadow_SetupEntityLight(ent);
4019 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
4021 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4024 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
4028 int numleafs, numsurfaces;
4029 int *leaflist, *surfacelist;
4030 unsigned char *leafpvs;
4031 unsigned char *shadowtrispvs;
4032 unsigned char *lighttrispvs;
4033 //unsigned char *surfacesides;
4034 int numlightentities;
4035 int numlightentities_noselfshadow;
4036 int numshadowentities;
4037 int numshadowentities_noselfshadow;
4038 static entity_render_t *lightentities[MAX_EDICTS];
4039 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
4040 static entity_render_t *shadowentities[MAX_EDICTS];
4041 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
4043 qboolean castshadows;
4045 rtlight->draw = false;
4046 rtlight->cached_numlightentities = 0;
4047 rtlight->cached_numlightentities_noselfshadow = 0;
4048 rtlight->cached_numshadowentities = 0;
4049 rtlight->cached_numshadowentities_noselfshadow = 0;
4050 rtlight->cached_numsurfaces = 0;
4051 rtlight->cached_lightentities = NULL;
4052 rtlight->cached_lightentities_noselfshadow = NULL;
4053 rtlight->cached_shadowentities = NULL;
4054 rtlight->cached_shadowentities_noselfshadow = NULL;
4055 rtlight->cached_shadowtrispvs = NULL;
4056 rtlight->cached_lighttrispvs = NULL;
4057 rtlight->cached_surfacelist = NULL;
4059 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
4060 // skip lights that are basically invisible (color 0 0 0)
4061 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
4063 // loading is done before visibility checks because loading should happen
4064 // all at once at the start of a level, not when it stalls gameplay.
4065 // (especially important to benchmarks)
4067 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
4069 if (rtlight->compiled)
4070 R_RTLight_Uncompile(rtlight);
4071 R_RTLight_Compile(rtlight);
4075 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
4077 // look up the light style value at this time
4078 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4079 VectorScale(rtlight->color, f, rtlight->currentcolor);
4081 if (rtlight->selected)
4083 f = 2 + sin(realtime * M_PI * 4.0);
4084 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
4088 // if lightstyle is currently off, don't draw the light
4089 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
4092 // skip processing on corona-only lights
4096 // if the light box is offscreen, skip it
4097 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
4100 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
4101 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
4103 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4105 // 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
4106 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
4109 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
4111 // compiled light, world available and can receive realtime lighting
4112 // retrieve leaf information
4113 numleafs = rtlight->static_numleafs;
4114 leaflist = rtlight->static_leaflist;
4115 leafpvs = rtlight->static_leafpvs;
4116 numsurfaces = rtlight->static_numsurfaces;
4117 surfacelist = rtlight->static_surfacelist;
4118 //surfacesides = NULL;
4119 shadowtrispvs = rtlight->static_shadowtrispvs;
4120 lighttrispvs = rtlight->static_lighttrispvs;
4122 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4124 // dynamic light, world available and can receive realtime lighting
4125 // calculate lit surfaces and leafs
4126 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);
4127 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4128 leaflist = r_shadow_buffer_leaflist;
4129 leafpvs = r_shadow_buffer_leafpvs;
4130 surfacelist = r_shadow_buffer_surfacelist;
4131 //surfacesides = r_shadow_buffer_surfacesides;
4132 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4133 lighttrispvs = r_shadow_buffer_lighttrispvs;
4134 // if the reduced leaf bounds are offscreen, skip it
4135 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4146 //surfacesides = NULL;
4147 shadowtrispvs = NULL;
4148 lighttrispvs = NULL;
4150 // check if light is illuminating any visible leafs
4153 for (i = 0;i < numleafs;i++)
4154 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4160 // make a list of lit entities and shadow casting entities
4161 numlightentities = 0;
4162 numlightentities_noselfshadow = 0;
4163 numshadowentities = 0;
4164 numshadowentities_noselfshadow = 0;
4166 // add dynamic entities that are lit by the light
4167 for (i = 0;i < r_refdef.scene.numentities;i++)
4170 entity_render_t *ent = r_refdef.scene.entities[i];
4172 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4174 // skip the object entirely if it is not within the valid
4175 // shadow-casting region (which includes the lit region)
4176 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
4178 if (!(model = ent->model))
4180 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4182 // this entity wants to receive light, is visible, and is
4183 // inside the light box
4184 // TODO: check if the surfaces in the model can receive light
4185 // so now check if it's in a leaf seen by the light
4186 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))
4188 if (ent->flags & RENDER_NOSELFSHADOW)
4189 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
4191 lightentities[numlightentities++] = ent;
4192 // since it is lit, it probably also casts a shadow...
4193 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4194 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4195 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4197 // note: exterior models without the RENDER_NOSELFSHADOW
4198 // flag still create a RENDER_NOSELFSHADOW shadow but
4199 // are lit normally, this means that they are
4200 // self-shadowing but do not shadow other
4201 // RENDER_NOSELFSHADOW entities such as the gun
4202 // (very weird, but keeps the player shadow off the gun)
4203 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4204 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4206 shadowentities[numshadowentities++] = ent;
4209 else if (ent->flags & RENDER_SHADOW)
4211 // this entity is not receiving light, but may still need to
4213 // TODO: check if the surfaces in the model can cast shadow
4214 // now check if it is in a leaf seen by the light
4215 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))
4217 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4218 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4219 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4221 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4222 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4224 shadowentities[numshadowentities++] = ent;
4229 // return if there's nothing at all to light
4230 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4233 // count this light in the r_speeds
4234 r_refdef.stats[r_stat_lights]++;
4236 // flag it as worth drawing later
4237 rtlight->draw = true;
4239 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
4240 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4242 numshadowentities = numshadowentities_noselfshadow = 0;
4244 // cache all the animated entities that cast a shadow but are not visible
4245 for (i = 0;i < numshadowentities;i++)
4246 R_AnimCache_GetEntity(shadowentities[i], false, false);
4247 for (i = 0;i < numshadowentities_noselfshadow;i++)
4248 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4250 // allocate some temporary memory for rendering this light later in the frame
4251 // reusable buffers need to be copied, static data can be used as-is
4252 rtlight->cached_numlightentities = numlightentities;
4253 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
4254 rtlight->cached_numshadowentities = numshadowentities;
4255 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4256 rtlight->cached_numsurfaces = numsurfaces;
4257 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4258 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4259 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4260 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4261 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4263 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4264 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4265 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4266 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4267 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4271 // compiled light data
4272 rtlight->cached_shadowtrispvs = shadowtrispvs;
4273 rtlight->cached_lighttrispvs = lighttrispvs;
4274 rtlight->cached_surfacelist = surfacelist;
4278 static void R_Shadow_DrawLight(rtlight_t *rtlight)
4282 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4283 int numlightentities;
4284 int numlightentities_noselfshadow;
4285 int numshadowentities;
4286 int numshadowentities_noselfshadow;
4287 entity_render_t **lightentities;
4288 entity_render_t **lightentities_noselfshadow;
4289 entity_render_t **shadowentities;
4290 entity_render_t **shadowentities_noselfshadow;
4292 static unsigned char entitysides[MAX_EDICTS];
4293 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4294 vec3_t nearestpoint;
4296 qboolean castshadows;
4299 // check if we cached this light this frame (meaning it is worth drawing)
4303 numlightentities = rtlight->cached_numlightentities;
4304 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4305 numshadowentities = rtlight->cached_numshadowentities;
4306 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4307 numsurfaces = rtlight->cached_numsurfaces;
4308 lightentities = rtlight->cached_lightentities;
4309 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4310 shadowentities = rtlight->cached_shadowentities;
4311 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4312 shadowtrispvs = rtlight->cached_shadowtrispvs;
4313 lighttrispvs = rtlight->cached_lighttrispvs;
4314 surfacelist = rtlight->cached_surfacelist;
4316 // set up a scissor rectangle for this light
4317 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4320 // don't let sound skip if going slow
4321 if (r_refdef.scene.extraupdate)
4324 // make this the active rtlight for rendering purposes
4325 R_Shadow_RenderMode_ActiveLight(rtlight);
4327 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4329 // optionally draw visible shape of the shadow volumes
4330 // for performance analysis by level designers
4331 R_Shadow_RenderMode_VisibleShadowVolumes();
4333 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4334 for (i = 0;i < numshadowentities;i++)
4335 R_Shadow_DrawEntityShadow(shadowentities[i]);
4336 for (i = 0;i < numshadowentities_noselfshadow;i++)
4337 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4338 R_Shadow_RenderMode_VisibleLighting(false, false);
4341 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4343 // optionally draw the illuminated areas
4344 // for performance analysis by level designers
4345 R_Shadow_RenderMode_VisibleLighting(false, false);
4347 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4348 for (i = 0;i < numlightentities;i++)
4349 R_Shadow_DrawEntityLight(lightentities[i]);
4350 for (i = 0;i < numlightentities_noselfshadow;i++)
4351 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4354 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4356 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4357 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4358 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4359 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4361 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
4362 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4363 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4365 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4371 int receivermask = 0;
4372 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4373 Matrix4x4_Abs(&radiustolight);
4375 r_shadow_shadowmaplod = 0;
4376 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4377 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
4378 r_shadow_shadowmaplod = i;
4380 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4382 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4384 surfacesides = NULL;
4387 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4389 castermask = rtlight->static_shadowmap_casters;
4390 receivermask = rtlight->static_shadowmap_receivers;
4394 surfacesides = r_shadow_buffer_surfacesides;
4395 for(i = 0;i < numsurfaces;i++)
4397 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4398 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4399 castermask |= surfacesides[i];
4400 receivermask |= surfacesides[i];
4404 if (receivermask < 0x3F)
4406 for (i = 0;i < numlightentities;i++)
4407 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4408 if (receivermask < 0x3F)
4409 for(i = 0; i < numlightentities_noselfshadow;i++)
4410 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4413 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4417 for (i = 0;i < numshadowentities;i++)
4418 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4419 for (i = 0;i < numshadowentities_noselfshadow;i++)
4420 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4423 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4425 // render shadow casters into 6 sided depth texture
4426 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4428 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
4429 if (! (castermask & (1 << side))) continue;
4431 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4432 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4433 R_Shadow_DrawEntityShadow(shadowentities[i]);
4436 if (numlightentities_noselfshadow)
4438 // render lighting using the depth texture as shadowmap
4439 // draw lighting in the unmasked areas
4440 R_Shadow_RenderMode_Lighting(false, false, true);
4441 for (i = 0;i < numlightentities_noselfshadow;i++)
4442 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4445 // render shadow casters into 6 sided depth texture
4446 if (numshadowentities_noselfshadow)
4448 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4450 R_Shadow_RenderMode_ShadowMap(side, 0, size);
4451 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
4452 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4456 // render lighting using the depth texture as shadowmap
4457 // draw lighting in the unmasked areas
4458 R_Shadow_RenderMode_Lighting(false, false, true);
4459 // draw lighting in the unmasked areas
4461 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4462 for (i = 0;i < numlightentities;i++)
4463 R_Shadow_DrawEntityLight(lightentities[i]);
4465 else if (castshadows && vid.stencil)
4467 // draw stencil shadow volumes to mask off pixels that are in shadow
4468 // so that they won't receive lighting
4469 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4470 R_Shadow_ClearStencil();
4473 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4474 for (i = 0;i < numshadowentities;i++)
4475 R_Shadow_DrawEntityShadow(shadowentities[i]);
4477 // draw lighting in the unmasked areas
4478 R_Shadow_RenderMode_Lighting(true, false, false);
4479 for (i = 0;i < numlightentities_noselfshadow;i++)
4480 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4482 for (i = 0;i < numshadowentities_noselfshadow;i++)
4483 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4485 // draw lighting in the unmasked areas
4486 R_Shadow_RenderMode_Lighting(true, false, false);
4488 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4489 for (i = 0;i < numlightentities;i++)
4490 R_Shadow_DrawEntityLight(lightentities[i]);
4494 // draw lighting in the unmasked areas
4495 R_Shadow_RenderMode_Lighting(false, false, false);
4497 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4498 for (i = 0;i < numlightentities;i++)
4499 R_Shadow_DrawEntityLight(lightentities[i]);
4500 for (i = 0;i < numlightentities_noselfshadow;i++)
4501 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4504 if (r_shadow_usingdeferredprepass)
4506 // when rendering deferred lighting, we simply rasterize the box
4507 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4508 R_Shadow_RenderMode_DrawDeferredLight(false, true);
4509 else if (castshadows && vid.stencil)
4510 R_Shadow_RenderMode_DrawDeferredLight(true, false);
4512 R_Shadow_RenderMode_DrawDeferredLight(false, false);
4516 static void R_Shadow_FreeDeferred(void)
4518 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
4519 r_shadow_prepassgeometryfbo = 0;
4521 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
4522 r_shadow_prepasslightingdiffusespecularfbo = 0;
4524 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
4525 r_shadow_prepasslightingdiffusefbo = 0;
4527 if (r_shadow_prepassgeometrydepthbuffer)
4528 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
4529 r_shadow_prepassgeometrydepthbuffer = NULL;
4531 if (r_shadow_prepassgeometrynormalmaptexture)
4532 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4533 r_shadow_prepassgeometrynormalmaptexture = NULL;
4535 if (r_shadow_prepasslightingdiffusetexture)
4536 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
4537 r_shadow_prepasslightingdiffusetexture = NULL;
4539 if (r_shadow_prepasslightingspeculartexture)
4540 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4541 r_shadow_prepasslightingspeculartexture = NULL;
4544 void R_Shadow_DrawPrepass(void)
4552 entity_render_t *ent;
4553 float clearcolor[4];
4555 R_Mesh_ResetTextureState();
4557 GL_ColorMask(1,1,1,1);
4558 GL_BlendFunc(GL_ONE, GL_ZERO);
4561 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4562 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4563 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4564 if (r_timereport_active)
4565 R_TimeReport("prepasscleargeom");
4567 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4568 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4569 if (r_timereport_active)
4570 R_TimeReport("prepassworld");
4572 for (i = 0;i < r_refdef.scene.numentities;i++)
4574 if (!r_refdef.viewcache.entityvisible[i])
4576 ent = r_refdef.scene.entities[i];
4577 if (ent->model && ent->model->DrawPrepass != NULL)
4578 ent->model->DrawPrepass(ent);
4581 if (r_timereport_active)
4582 R_TimeReport("prepassmodels");
4584 GL_DepthMask(false);
4585 GL_ColorMask(1,1,1,1);
4588 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4589 Vector4Set(clearcolor, 0, 0, 0, 0);
4590 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4591 if (r_timereport_active)
4592 R_TimeReport("prepassclearlit");
4594 R_Shadow_RenderMode_Begin();
4596 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4597 if (r_shadow_debuglight.integer >= 0)
4599 lightindex = r_shadow_debuglight.integer;
4600 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4601 if (light && (light->flags & flag) && light->rtlight.draw)
4602 R_Shadow_DrawLight(&light->rtlight);
4606 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4607 for (lightindex = 0;lightindex < range;lightindex++)
4609 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4610 if (light && (light->flags & flag) && light->rtlight.draw)
4611 R_Shadow_DrawLight(&light->rtlight);
4614 if (r_refdef.scene.rtdlight)
4615 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4616 if (r_refdef.scene.lights[lnum]->draw)
4617 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4619 R_Shadow_RenderMode_End();
4621 if (r_timereport_active)
4622 R_TimeReport("prepasslights");
4625 void R_Shadow_DrawLightSprites(void);
4626 void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
4635 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4636 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4637 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
4638 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4639 r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) ||
4640 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4641 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16) ||
4642 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
4643 R_Shadow_FreeShadowMaps();
4645 r_shadow_fb_fbo = fbo;
4646 r_shadow_fb_depthtexture = depthtexture;
4647 r_shadow_fb_colortexture = colortexture;
4649 r_shadow_usingshadowmaportho = false;
4651 switch (vid.renderpath)
4653 case RENDERPATH_GL20:
4654 case RENDERPATH_D3D9:
4655 case RENDERPATH_D3D10:
4656 case RENDERPATH_D3D11:
4657 case RENDERPATH_SOFT:
4659 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4661 r_shadow_usingdeferredprepass = false;
4662 if (r_shadow_prepass_width)
4663 R_Shadow_FreeDeferred();
4664 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4668 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4670 R_Shadow_FreeDeferred();
4672 r_shadow_usingdeferredprepass = true;
4673 r_shadow_prepass_width = vid.width;
4674 r_shadow_prepass_height = vid.height;
4675 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
4676 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);
4677 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);
4678 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);
4680 // set up the geometry pass fbo (depth + normalmap)
4681 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4682 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4683 // render depth into a renderbuffer and other important properties into the normalmap texture
4685 // set up the lighting pass fbo (diffuse + specular)
4686 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4687 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4688 // render diffuse into one texture and specular into another,
4689 // with depth and normalmap bound as textures,
4690 // with depth bound as attachment as well
4692 // set up the lighting pass fbo (diffuse)
4693 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4694 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4695 // render diffuse into one texture,
4696 // with depth and normalmap bound as textures,
4697 // with depth bound as attachment as well
4701 case RENDERPATH_GL11:
4702 case RENDERPATH_GL13:
4703 case RENDERPATH_GLES1:
4704 case RENDERPATH_GLES2:
4705 r_shadow_usingdeferredprepass = false;
4709 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);
4711 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4712 if (r_shadow_debuglight.integer >= 0)
4714 lightindex = r_shadow_debuglight.integer;
4715 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4717 R_Shadow_PrepareLight(&light->rtlight);
4721 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4722 for (lightindex = 0;lightindex < range;lightindex++)
4724 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4725 if (light && (light->flags & flag))
4726 R_Shadow_PrepareLight(&light->rtlight);
4729 if (r_refdef.scene.rtdlight)
4731 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4732 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4734 else if(gl_flashblend.integer)
4736 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4738 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4739 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4740 VectorScale(rtlight->color, f, rtlight->currentcolor);
4744 if (r_editlights.integer)
4745 R_Shadow_DrawLightSprites();
4748 void R_Shadow_DrawLights(void)
4756 R_Shadow_RenderMode_Begin();
4758 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4759 if (r_shadow_debuglight.integer >= 0)
4761 lightindex = r_shadow_debuglight.integer;
4762 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4764 R_Shadow_DrawLight(&light->rtlight);
4768 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4769 for (lightindex = 0;lightindex < range;lightindex++)
4771 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4772 if (light && (light->flags & flag))
4773 R_Shadow_DrawLight(&light->rtlight);
4776 if (r_refdef.scene.rtdlight)
4777 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4778 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4780 R_Shadow_RenderMode_End();
4783 #define MAX_MODELSHADOWS 1024
4784 static int r_shadow_nummodelshadows;
4785 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
4787 void R_Shadow_PrepareModelShadows(void)
4790 float scale, size, radius, dot1, dot2;
4791 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4792 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4793 entity_render_t *ent;
4795 r_shadow_nummodelshadows = 0;
4796 if (!r_refdef.scene.numentities)
4799 switch (r_shadow_shadowmode)
4801 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4802 if (r_shadows.integer >= 2)
4805 case R_SHADOW_SHADOWMODE_STENCIL:
4808 for (i = 0;i < r_refdef.scene.numentities;i++)
4810 ent = r_refdef.scene.entities[i];
4811 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4813 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
4815 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
4816 R_AnimCache_GetEntity(ent, false, false);
4824 size = 2*r_shadow_shadowmapmaxsize;
4825 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4826 radius = 0.5f * size / scale;
4828 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4829 VectorCopy(prvmshadowdir, shadowdir);
4830 VectorNormalize(shadowdir);
4831 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4832 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4833 if (fabs(dot1) <= fabs(dot2))
4834 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4836 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4837 VectorNormalize(shadowforward);
4838 CrossProduct(shadowdir, shadowforward, shadowright);
4839 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4840 VectorCopy(prvmshadowfocus, shadowfocus);
4841 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4842 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4843 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4844 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4845 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4847 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4849 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4850 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4851 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4852 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4853 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4854 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4856 for (i = 0;i < r_refdef.scene.numentities;i++)
4858 ent = r_refdef.scene.entities[i];
4859 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4861 // cast shadows from anything of the map (submodels are optional)
4862 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4864 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
4866 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
4867 R_AnimCache_GetEntity(ent, false, false);
4872 void R_DrawModelShadowMaps(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
4875 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4876 entity_render_t *ent;
4877 vec3_t relativelightorigin;
4878 vec3_t relativelightdirection, relativeforward, relativeright;
4879 vec3_t relativeshadowmins, relativeshadowmaxs;
4880 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4881 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4883 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4884 r_viewport_t viewport;
4885 GLuint shadowfbo = 0;
4886 float clearcolor[4];
4888 if (!r_shadow_nummodelshadows)
4891 switch (r_shadow_shadowmode)
4893 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4899 r_shadow_fb_fbo = fbo;
4900 r_shadow_fb_depthtexture = depthtexture;
4901 r_shadow_fb_colortexture = colortexture;
4903 R_ResetViewRendering3D(fbo, depthtexture, colortexture);
4904 R_Shadow_RenderMode_Begin();
4905 R_Shadow_RenderMode_ActiveLight(NULL);
4907 switch (r_shadow_shadowmode)
4909 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4910 if (!r_shadow_shadowmap2ddepthtexture)
4911 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4912 shadowfbo = r_shadow_fbo2d;
4913 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
4914 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
4915 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4921 size = 2*r_shadow_shadowmapmaxsize;
4922 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4923 radius = 0.5f / scale;
4924 nearclip = -r_shadows_throwdistance.value;
4925 farclip = r_shadows_throwdistance.value;
4926 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);
4928 r_shadow_shadowmap_parameters[0] = size;
4929 r_shadow_shadowmap_parameters[1] = size;
4930 r_shadow_shadowmap_parameters[2] = 1.0;
4931 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4933 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4934 VectorCopy(prvmshadowdir, shadowdir);
4935 VectorNormalize(shadowdir);
4936 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4937 VectorCopy(prvmshadowfocus, shadowfocus);
4938 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4939 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4940 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4941 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4942 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4943 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4944 if (fabs(dot1) <= fabs(dot2))
4945 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4947 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4948 VectorNormalize(shadowforward);
4949 VectorM(scale, shadowforward, &m[0]);
4950 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4952 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4953 CrossProduct(shadowdir, shadowforward, shadowright);
4954 VectorM(scale, shadowright, &m[4]);
4955 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4956 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4957 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4958 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4959 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4960 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4962 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4964 if (r_shadow_shadowmap2ddepthbuffer)
4965 R_Mesh_SetRenderTargets(shadowfbo, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
4967 R_Mesh_SetRenderTargets(shadowfbo, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
4968 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
4969 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4972 R_SetViewport(&viewport);
4973 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4974 Vector4Set(clearcolor, 1,1,1,1);
4975 // in D3D9 we have to render to a color texture shadowmap
4976 // in GL we render directly to a depth texture only
4977 if (r_shadow_shadowmap2ddepthbuffer)
4978 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4980 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4981 // render into a slightly restricted region so that the borders of the
4982 // shadowmap area fade away, rather than streaking across everything
4983 // outside the usable area
4984 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4986 for (i = 0;i < r_shadow_nummodelshadows;i++)
4988 ent = r_shadow_modelshadows[i];
4989 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4990 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4991 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4992 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4993 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4994 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4995 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4996 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4997 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4998 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4999 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5000 RSurf_ActiveModelEntity(ent, false, false, false);
5001 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
5002 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5008 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
5010 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
5012 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
5013 Cvar_SetValueQuick(&r_test, 0);
5018 R_Shadow_RenderMode_End();
5020 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
5021 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
5022 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
5023 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
5024 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
5025 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
5027 switch (vid.renderpath)
5029 case RENDERPATH_GL11:
5030 case RENDERPATH_GL13:
5031 case RENDERPATH_GL20:
5032 case RENDERPATH_SOFT:
5033 case RENDERPATH_GLES1:
5034 case RENDERPATH_GLES2:
5036 case RENDERPATH_D3D9:
5037 case RENDERPATH_D3D10:
5038 case RENDERPATH_D3D11:
5039 #ifdef MATRIX4x4_OPENGLORIENTATION
5040 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5041 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
5042 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
5043 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
5045 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5046 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
5047 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
5048 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
5053 r_shadow_usingshadowmaportho = true;
5054 switch (r_shadow_shadowmode)
5056 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
5057 r_shadow_usingshadowmap2d = true;
5064 void R_DrawModelShadows(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
5067 float relativethrowdistance;
5068 entity_render_t *ent;
5069 vec3_t relativelightorigin;
5070 vec3_t relativelightdirection;
5071 vec3_t relativeshadowmins, relativeshadowmaxs;
5072 vec3_t tmp, shadowdir;
5073 prvm_vec3_t prvmshadowdir;
5075 if (!r_shadow_nummodelshadows || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
5078 r_shadow_fb_fbo = fbo;
5079 r_shadow_fb_depthtexture = depthtexture;
5080 r_shadow_fb_colortexture = colortexture;
5082 R_ResetViewRendering3D(fbo, depthtexture, colortexture);
5083 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
5084 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5085 R_Shadow_RenderMode_Begin();
5086 R_Shadow_RenderMode_ActiveLight(NULL);
5087 r_shadow_lightscissor[0] = r_refdef.view.x;
5088 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
5089 r_shadow_lightscissor[2] = r_refdef.view.width;
5090 r_shadow_lightscissor[3] = r_refdef.view.height;
5091 R_Shadow_RenderMode_StencilShadowVolumes(false);
5094 if (r_shadows.integer == 2)
5096 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5097 VectorCopy(prvmshadowdir, shadowdir);
5098 VectorNormalize(shadowdir);
5101 R_Shadow_ClearStencil();
5103 for (i = 0;i < r_shadow_nummodelshadows;i++)
5105 ent = r_shadow_modelshadows[i];
5107 // cast shadows from anything of the map (submodels are optional)
5108 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5109 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
5110 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
5111 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
5112 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5115 if(ent->entitynumber != 0)
5117 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
5119 // FIXME handle this
5120 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5124 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
5125 int entnum, entnum2, recursion;
5126 entnum = entnum2 = ent->entitynumber;
5127 for(recursion = 32; recursion > 0; --recursion)
5129 entnum2 = cl.entities[entnum].state_current.tagentity;
5130 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
5135 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
5137 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
5138 // transform into modelspace of OUR entity
5139 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
5140 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
5143 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5147 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5150 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
5151 RSurf_ActiveModelEntity(ent, false, false, false);
5152 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
5153 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5156 // not really the right mode, but this will disable any silly stencil features
5157 R_Shadow_RenderMode_End();
5159 // set up ortho view for rendering this pass
5160 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5161 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5162 //GL_ScissorTest(true);
5163 //R_EntityMatrix(&identitymatrix);
5164 //R_Mesh_ResetTextureState();
5165 R_ResetViewRendering2D(fbo, depthtexture, colortexture);
5167 // set up a darkening blend on shadowed areas
5168 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5169 //GL_DepthRange(0, 1);
5170 //GL_DepthTest(false);
5171 //GL_DepthMask(false);
5172 //GL_PolygonOffset(0, 0);CHECKGLERROR
5173 GL_Color(0, 0, 0, r_shadows_darken.value);
5174 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5175 //GL_DepthFunc(GL_ALWAYS);
5176 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5178 // apply the blend to the shadowed areas
5179 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5180 R_SetupShader_Generic_NoTexture(false, true);
5181 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5183 // restore the viewport
5184 R_SetViewport(&r_refdef.view.viewport);
5186 // restore other state to normal
5187 //R_Shadow_RenderMode_End();
5190 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5193 vec3_t centerorigin;
5194 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5197 // if it's too close, skip it
5198 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5200 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5203 if (usequery && r_numqueries + 2 <= r_maxqueries)
5205 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5206 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5207 // 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
5208 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5210 switch(vid.renderpath)
5212 case RENDERPATH_GL11:
5213 case RENDERPATH_GL13:
5214 case RENDERPATH_GL20:
5215 case RENDERPATH_GLES1:
5216 case RENDERPATH_GLES2:
5217 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5219 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5220 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5221 GL_DepthFunc(GL_ALWAYS);
5222 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5223 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5224 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5225 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5226 GL_DepthFunc(GL_LEQUAL);
5227 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5228 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5229 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5230 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5231 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5235 case RENDERPATH_D3D9:
5236 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5238 case RENDERPATH_D3D10:
5239 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5241 case RENDERPATH_D3D11:
5242 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5244 case RENDERPATH_SOFT:
5245 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5249 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5252 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5254 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5257 unsigned int occlude = 0;
5258 GLint allpixels = 0, visiblepixels = 0;
5260 // now we have to check the query result
5261 if (rtlight->corona_queryindex_visiblepixels)
5263 switch(vid.renderpath)
5265 case RENDERPATH_GL11:
5266 case RENDERPATH_GL13:
5267 case RENDERPATH_GL20:
5268 case RENDERPATH_GLES1:
5269 case RENDERPATH_GLES2:
5270 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5272 // See if we can use the GPU-side method to prevent implicit sync
5273 if (vid.support.arb_query_buffer_object) {
5274 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
5275 if (!r_shadow_occlusion_buf) {
5276 qglGenBuffersARB(1, &r_shadow_occlusion_buf);
5277 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5278 qglBufferDataARB(GL_QUERY_BUFFER_ARB, 8, NULL, GL_DYNAMIC_COPY);
5280 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5282 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(0));
5283 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4));
5284 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
5285 occlude = MATERIALFLAG_OCCLUDE;
5287 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5288 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5289 if (visiblepixels < 1 || allpixels < 1)
5291 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5293 cscale *= rtlight->corona_visibility;
5299 case RENDERPATH_D3D9:
5300 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5302 case RENDERPATH_D3D10:
5303 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5305 case RENDERPATH_D3D11:
5306 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5308 case RENDERPATH_SOFT:
5309 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5317 // FIXME: these traces should scan all render entities instead of cl.world
5318 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
5321 VectorScale(rtlight->currentcolor, cscale, color);
5322 if (VectorLength(color) > (1.0f / 256.0f))
5325 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
5328 VectorNegate(color, color);
5329 GL_BlendEquationSubtract(true);
5331 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5332 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);
5333 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
5335 GL_BlendEquationSubtract(false);
5339 void R_Shadow_DrawCoronas(void)
5342 qboolean usequery = false;
5347 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
5349 if (r_fb.water.renderingscene)
5351 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5352 R_EntityMatrix(&identitymatrix);
5354 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5356 // check occlusion of coronas
5357 // use GL_ARB_occlusion_query if available
5358 // otherwise use raytraces
5360 switch (vid.renderpath)
5362 case RENDERPATH_GL11:
5363 case RENDERPATH_GL13:
5364 case RENDERPATH_GL20:
5365 case RENDERPATH_GLES1:
5366 case RENDERPATH_GLES2:
5367 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
5368 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5371 GL_ColorMask(0,0,0,0);
5372 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
5373 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
5376 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
5377 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
5379 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
5382 RSurf_ActiveWorldEntity();
5383 GL_BlendFunc(GL_ONE, GL_ZERO);
5384 GL_CullFace(GL_NONE);
5385 GL_DepthMask(false);
5386 GL_DepthRange(0, 1);
5387 GL_PolygonOffset(0, 0);
5389 R_Mesh_ResetTextureState();
5390 R_SetupShader_Generic_NoTexture(false, false);
5394 case RENDERPATH_D3D9:
5396 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5398 case RENDERPATH_D3D10:
5399 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5401 case RENDERPATH_D3D11:
5402 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5404 case RENDERPATH_SOFT:
5406 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5409 for (lightindex = 0;lightindex < range;lightindex++)
5411 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5414 rtlight = &light->rtlight;
5415 rtlight->corona_visibility = 0;
5416 rtlight->corona_queryindex_visiblepixels = 0;
5417 rtlight->corona_queryindex_allpixels = 0;
5418 if (!(rtlight->flags & flag))
5420 if (rtlight->corona <= 0)
5422 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
5424 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5426 for (i = 0;i < r_refdef.scene.numlights;i++)
5428 rtlight = r_refdef.scene.lights[i];
5429 rtlight->corona_visibility = 0;
5430 rtlight->corona_queryindex_visiblepixels = 0;
5431 rtlight->corona_queryindex_allpixels = 0;
5432 if (!(rtlight->flags & flag))
5434 if (rtlight->corona <= 0)
5436 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5439 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5441 // now draw the coronas using the query data for intensity info
5442 for (lightindex = 0;lightindex < range;lightindex++)
5444 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5447 rtlight = &light->rtlight;
5448 if (rtlight->corona_visibility <= 0)
5450 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5452 for (i = 0;i < r_refdef.scene.numlights;i++)
5454 rtlight = r_refdef.scene.lights[i];
5455 if (rtlight->corona_visibility <= 0)
5457 if (gl_flashblend.integer)
5458 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
5460 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5466 static dlight_t *R_Shadow_NewWorldLight(void)
5468 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
5471 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)
5475 // 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
5477 // validate parameters
5481 // copy to light properties
5482 VectorCopy(origin, light->origin);
5483 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
5484 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
5485 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
5487 light->color[0] = max(color[0], 0);
5488 light->color[1] = max(color[1], 0);
5489 light->color[2] = max(color[2], 0);
5491 light->color[0] = color[0];
5492 light->color[1] = color[1];
5493 light->color[2] = color[2];
5494 light->radius = max(radius, 0);
5495 light->style = style;
5496 light->shadow = shadowenable;
5497 light->corona = corona;
5498 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
5499 light->coronasizescale = coronasizescale;
5500 light->ambientscale = ambientscale;
5501 light->diffusescale = diffusescale;
5502 light->specularscale = specularscale;
5503 light->flags = flags;
5505 // update renderable light data
5506 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
5507 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);
5510 static void R_Shadow_FreeWorldLight(dlight_t *light)
5512 if (r_shadow_selectedlight == light)
5513 r_shadow_selectedlight = NULL;
5514 R_RTLight_Uncompile(&light->rtlight);
5515 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
5518 void R_Shadow_ClearWorldLights(void)
5522 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5523 for (lightindex = 0;lightindex < range;lightindex++)
5525 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5527 R_Shadow_FreeWorldLight(light);
5529 r_shadow_selectedlight = NULL;
5532 static void R_Shadow_SelectLight(dlight_t *light)
5534 if (r_shadow_selectedlight)
5535 r_shadow_selectedlight->selected = false;
5536 r_shadow_selectedlight = light;
5537 if (r_shadow_selectedlight)
5538 r_shadow_selectedlight->selected = true;
5541 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5543 // this is never batched (there can be only one)
5545 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
5546 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5547 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5550 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5555 skinframe_t *skinframe;
5558 // this is never batched (due to the ent parameter changing every time)
5559 // so numsurfaces == 1 and surfacelist[0] == lightnumber
5560 const dlight_t *light = (dlight_t *)ent;
5563 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
5566 VectorScale(light->color, intensity, spritecolor);
5567 if (VectorLength(spritecolor) < 0.1732f)
5568 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
5569 if (VectorLength(spritecolor) > 1.0f)
5570 VectorNormalize(spritecolor);
5572 // draw light sprite
5573 if (light->cubemapname[0] && !light->shadow)
5574 skinframe = r_editlights_sprcubemapnoshadowlight;
5575 else if (light->cubemapname[0])
5576 skinframe = r_editlights_sprcubemaplight;
5577 else if (!light->shadow)
5578 skinframe = r_editlights_sprnoshadowlight;
5580 skinframe = r_editlights_sprlight;
5582 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);
5583 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5585 // draw selection sprite if light is selected
5586 if (light->selected)
5588 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5589 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5590 // VorteX todo: add normalmode/realtime mode light overlay sprites?
5594 void R_Shadow_DrawLightSprites(void)
5598 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5599 for (lightindex = 0;lightindex < range;lightindex++)
5601 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5603 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
5605 if (!r_editlights_lockcursor)
5606 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
5609 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
5614 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
5615 if (lightindex >= range)
5617 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5620 rtlight = &light->rtlight;
5621 //if (!(rtlight->flags & flag))
5623 VectorCopy(rtlight->shadoworigin, origin);
5624 *radius = rtlight->radius;
5625 VectorCopy(rtlight->color, color);
5629 static void R_Shadow_SelectLightInView(void)
5631 float bestrating, rating, temp[3];
5635 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5639 if (r_editlights_lockcursor)
5641 for (lightindex = 0;lightindex < range;lightindex++)
5643 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5646 VectorSubtract(light->origin, r_refdef.view.origin, temp);
5647 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
5650 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
5651 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)
5653 bestrating = rating;
5658 R_Shadow_SelectLight(best);
5661 void R_Shadow_LoadWorldLights(void)
5663 int n, a, style, shadow, flags;
5664 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
5665 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
5666 if (cl.worldmodel == NULL)
5668 Con_Print("No map loaded.\n");
5671 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5672 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5682 for (;COM_Parse(t, true) && strcmp(
5683 if (COM_Parse(t, true))
5685 if (com_token[0] == '!')
5688 origin[0] = atof(com_token+1);
5691 origin[0] = atof(com_token);
5696 while (*s && *s != '\n' && *s != '\r')
5702 // check for modifier flags
5709 #if _MSC_VER >= 1400
5710 #define sscanf sscanf_s
5712 cubemapname[sizeof(cubemapname)-1] = 0;
5713 #if MAX_QPATH != 128
5714 #error update this code if MAX_QPATH changes
5716 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
5717 #if _MSC_VER >= 1400
5718 , sizeof(cubemapname)
5720 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5723 flags = LIGHTFLAG_REALTIMEMODE;
5731 coronasizescale = 0.25f;
5733 VectorClear(angles);
5736 if (a < 9 || !strcmp(cubemapname, "\"\""))
5738 // remove quotes on cubemapname
5739 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5742 namelen = strlen(cubemapname) - 2;
5743 memmove(cubemapname, cubemapname + 1, namelen);
5744 cubemapname[namelen] = '\0';
5748 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);
5751 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5759 Con_Printf("invalid rtlights file \"%s\"\n", name);
5760 Mem_Free(lightsstring);
5764 void R_Shadow_SaveWorldLights(void)
5768 size_t bufchars, bufmaxchars;
5770 char name[MAX_QPATH];
5771 char line[MAX_INPUTLINE];
5772 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5773 // I hate lines which are 3 times my screen size :( --blub
5776 if (cl.worldmodel == NULL)
5778 Con_Print("No map loaded.\n");
5781 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5782 bufchars = bufmaxchars = 0;
5784 for (lightindex = 0;lightindex < range;lightindex++)
5786 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5789 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5790 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);
5791 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5792 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]);
5794 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);
5795 if (bufchars + strlen(line) > bufmaxchars)
5797 bufmaxchars = bufchars + strlen(line) + 2048;
5799 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5803 memcpy(buf, oldbuf, bufchars);
5809 memcpy(buf + bufchars, line, strlen(line));
5810 bufchars += strlen(line);
5814 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5819 void R_Shadow_LoadLightsFile(void)
5822 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5823 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5824 if (cl.worldmodel == NULL)
5826 Con_Print("No map loaded.\n");
5829 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5830 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5838 while (*s && *s != '\n' && *s != '\r')
5844 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);
5848 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);
5851 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5852 radius = bound(15, radius, 4096);
5853 VectorScale(color, (2.0f / (8388608.0f)), color);
5854 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5862 Con_Printf("invalid lights file \"%s\"\n", name);
5863 Mem_Free(lightsstring);
5867 // tyrlite/hmap2 light types in the delay field
5868 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5870 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5882 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5883 char key[256], value[MAX_INPUTLINE];
5886 if (cl.worldmodel == NULL)
5888 Con_Print("No map loaded.\n");
5891 // try to load a .ent file first
5892 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5893 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5894 // and if that is not found, fall back to the bsp file entity string
5896 data = cl.worldmodel->brush.entities;
5899 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
5901 type = LIGHTTYPE_MINUSX;
5902 origin[0] = origin[1] = origin[2] = 0;
5903 originhack[0] = originhack[1] = originhack[2] = 0;
5904 angles[0] = angles[1] = angles[2] = 0;
5905 color[0] = color[1] = color[2] = 1;
5906 light[0] = light[1] = light[2] = 1;light[3] = 300;
5907 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5917 if (!COM_ParseToken_Simple(&data, false, false, true))
5919 if (com_token[0] == '}')
5920 break; // end of entity
5921 if (com_token[0] == '_')
5922 strlcpy(key, com_token + 1, sizeof(key));
5924 strlcpy(key, com_token, sizeof(key));
5925 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5926 key[strlen(key)-1] = 0;
5927 if (!COM_ParseToken_Simple(&data, false, false, true))
5929 strlcpy(value, com_token, sizeof(value));
5931 // now that we have the key pair worked out...
5932 if (!strcmp("light", key))
5934 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5938 light[0] = vec[0] * (1.0f / 256.0f);
5939 light[1] = vec[0] * (1.0f / 256.0f);
5940 light[2] = vec[0] * (1.0f / 256.0f);
5946 light[0] = vec[0] * (1.0f / 255.0f);
5947 light[1] = vec[1] * (1.0f / 255.0f);
5948 light[2] = vec[2] * (1.0f / 255.0f);
5952 else if (!strcmp("delay", key))
5954 else if (!strcmp("origin", key))
5955 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5956 else if (!strcmp("angle", key))
5957 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5958 else if (!strcmp("angles", key))
5959 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5960 else if (!strcmp("color", key))
5961 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5962 else if (!strcmp("wait", key))
5963 fadescale = atof(value);
5964 else if (!strcmp("classname", key))
5966 if (!strncmp(value, "light", 5))
5969 if (!strcmp(value, "light_fluoro"))
5974 overridecolor[0] = 1;
5975 overridecolor[1] = 1;
5976 overridecolor[2] = 1;
5978 if (!strcmp(value, "light_fluorospark"))
5983 overridecolor[0] = 1;
5984 overridecolor[1] = 1;
5985 overridecolor[2] = 1;
5987 if (!strcmp(value, "light_globe"))
5992 overridecolor[0] = 1;
5993 overridecolor[1] = 0.8;
5994 overridecolor[2] = 0.4;
5996 if (!strcmp(value, "light_flame_large_yellow"))
6001 overridecolor[0] = 1;
6002 overridecolor[1] = 0.5;
6003 overridecolor[2] = 0.1;
6005 if (!strcmp(value, "light_flame_small_yellow"))
6010 overridecolor[0] = 1;
6011 overridecolor[1] = 0.5;
6012 overridecolor[2] = 0.1;
6014 if (!strcmp(value, "light_torch_small_white"))
6019 overridecolor[0] = 1;
6020 overridecolor[1] = 0.5;
6021 overridecolor[2] = 0.1;
6023 if (!strcmp(value, "light_torch_small_walltorch"))
6028 overridecolor[0] = 1;
6029 overridecolor[1] = 0.5;
6030 overridecolor[2] = 0.1;
6034 else if (!strcmp("style", key))
6035 style = atoi(value);
6036 else if (!strcmp("skin", key))
6037 skin = (int)atof(value);
6038 else if (!strcmp("pflags", key))
6039 pflags = (int)atof(value);
6040 //else if (!strcmp("effects", key))
6041 // effects = (int)atof(value);
6042 else if (cl.worldmodel->type == mod_brushq3)
6044 if (!strcmp("scale", key))
6045 lightscale = atof(value);
6046 if (!strcmp("fade", key))
6047 fadescale = atof(value);
6052 if (lightscale <= 0)
6056 if (color[0] == color[1] && color[0] == color[2])
6058 color[0] *= overridecolor[0];
6059 color[1] *= overridecolor[1];
6060 color[2] *= overridecolor[2];
6062 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
6063 color[0] = color[0] * light[0];
6064 color[1] = color[1] * light[1];
6065 color[2] = color[2] * light[2];
6068 case LIGHTTYPE_MINUSX:
6070 case LIGHTTYPE_RECIPX:
6072 VectorScale(color, (1.0f / 16.0f), color);
6074 case LIGHTTYPE_RECIPXX:
6076 VectorScale(color, (1.0f / 16.0f), color);
6079 case LIGHTTYPE_NONE:
6083 case LIGHTTYPE_MINUSXX:
6086 VectorAdd(origin, originhack, origin);
6088 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);
6091 Mem_Free(entfiledata);
6095 static void R_Shadow_SetCursorLocationForView(void)
6098 vec3_t dest, endpos;
6100 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
6101 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true);
6102 if (trace.fraction < 1)
6104 dist = trace.fraction * r_editlights_cursordistance.value;
6105 push = r_editlights_cursorpushback.value;
6109 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
6110 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
6114 VectorClear( endpos );
6116 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6117 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6118 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6121 void R_Shadow_UpdateWorldLightSelection(void)
6123 if (r_editlights.integer)
6125 R_Shadow_SetCursorLocationForView();
6126 R_Shadow_SelectLightInView();
6129 R_Shadow_SelectLight(NULL);
6132 static void R_Shadow_EditLights_Clear_f(void)
6134 R_Shadow_ClearWorldLights();
6137 void R_Shadow_EditLights_Reload_f(void)
6141 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
6142 R_Shadow_ClearWorldLights();
6143 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
6145 R_Shadow_LoadWorldLights();
6146 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6147 R_Shadow_LoadLightsFile();
6149 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
6151 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6152 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6156 static void R_Shadow_EditLights_Save_f(void)
6160 R_Shadow_SaveWorldLights();
6163 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6165 R_Shadow_ClearWorldLights();
6166 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6169 static void R_Shadow_EditLights_ImportLightsFile_f(void)
6171 R_Shadow_ClearWorldLights();
6172 R_Shadow_LoadLightsFile();
6175 static void R_Shadow_EditLights_Spawn_f(void)
6178 if (!r_editlights.integer)
6180 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6183 if (Cmd_Argc() != 1)
6185 Con_Print("r_editlights_spawn does not take parameters\n");
6188 color[0] = color[1] = color[2] = 1;
6189 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6192 static void R_Shadow_EditLights_Edit_f(void)
6194 vec3_t origin, angles, color;
6195 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6196 int style, shadows, flags, normalmode, realtimemode;
6197 char cubemapname[MAX_INPUTLINE];
6198 if (!r_editlights.integer)
6200 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6203 if (!r_shadow_selectedlight)
6205 Con_Print("No selected light.\n");
6208 VectorCopy(r_shadow_selectedlight->origin, origin);
6209 VectorCopy(r_shadow_selectedlight->angles, angles);
6210 VectorCopy(r_shadow_selectedlight->color, color);
6211 radius = r_shadow_selectedlight->radius;
6212 style = r_shadow_selectedlight->style;
6213 if (r_shadow_selectedlight->cubemapname)
6214 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6217 shadows = r_shadow_selectedlight->shadow;
6218 corona = r_shadow_selectedlight->corona;
6219 coronasizescale = r_shadow_selectedlight->coronasizescale;
6220 ambientscale = r_shadow_selectedlight->ambientscale;
6221 diffusescale = r_shadow_selectedlight->diffusescale;
6222 specularscale = r_shadow_selectedlight->specularscale;
6223 flags = r_shadow_selectedlight->flags;
6224 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6225 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6226 if (!strcmp(Cmd_Argv(1), "origin"))
6228 if (Cmd_Argc() != 5)
6230 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6233 origin[0] = atof(Cmd_Argv(2));
6234 origin[1] = atof(Cmd_Argv(3));
6235 origin[2] = atof(Cmd_Argv(4));
6237 else if (!strcmp(Cmd_Argv(1), "originscale"))
6239 if (Cmd_Argc() != 5)
6241 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6244 origin[0] *= atof(Cmd_Argv(2));
6245 origin[1] *= atof(Cmd_Argv(3));
6246 origin[2] *= atof(Cmd_Argv(4));
6248 else if (!strcmp(Cmd_Argv(1), "originx"))
6250 if (Cmd_Argc() != 3)
6252 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6255 origin[0] = atof(Cmd_Argv(2));
6257 else if (!strcmp(Cmd_Argv(1), "originy"))
6259 if (Cmd_Argc() != 3)
6261 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6264 origin[1] = atof(Cmd_Argv(2));
6266 else if (!strcmp(Cmd_Argv(1), "originz"))
6268 if (Cmd_Argc() != 3)
6270 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6273 origin[2] = atof(Cmd_Argv(2));
6275 else if (!strcmp(Cmd_Argv(1), "move"))
6277 if (Cmd_Argc() != 5)
6279 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6282 origin[0] += atof(Cmd_Argv(2));
6283 origin[1] += atof(Cmd_Argv(3));
6284 origin[2] += atof(Cmd_Argv(4));
6286 else if (!strcmp(Cmd_Argv(1), "movex"))
6288 if (Cmd_Argc() != 3)
6290 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6293 origin[0] += atof(Cmd_Argv(2));
6295 else if (!strcmp(Cmd_Argv(1), "movey"))
6297 if (Cmd_Argc() != 3)
6299 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6302 origin[1] += atof(Cmd_Argv(2));
6304 else if (!strcmp(Cmd_Argv(1), "movez"))
6306 if (Cmd_Argc() != 3)
6308 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6311 origin[2] += atof(Cmd_Argv(2));
6313 else if (!strcmp(Cmd_Argv(1), "angles"))
6315 if (Cmd_Argc() != 5)
6317 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6320 angles[0] = atof(Cmd_Argv(2));
6321 angles[1] = atof(Cmd_Argv(3));
6322 angles[2] = atof(Cmd_Argv(4));
6324 else if (!strcmp(Cmd_Argv(1), "anglesx"))
6326 if (Cmd_Argc() != 3)
6328 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6331 angles[0] = atof(Cmd_Argv(2));
6333 else if (!strcmp(Cmd_Argv(1), "anglesy"))
6335 if (Cmd_Argc() != 3)
6337 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6340 angles[1] = atof(Cmd_Argv(2));
6342 else if (!strcmp(Cmd_Argv(1), "anglesz"))
6344 if (Cmd_Argc() != 3)
6346 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6349 angles[2] = atof(Cmd_Argv(2));
6351 else if (!strcmp(Cmd_Argv(1), "color"))
6353 if (Cmd_Argc() != 5)
6355 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
6358 color[0] = atof(Cmd_Argv(2));
6359 color[1] = atof(Cmd_Argv(3));
6360 color[2] = atof(Cmd_Argv(4));
6362 else if (!strcmp(Cmd_Argv(1), "radius"))
6364 if (Cmd_Argc() != 3)
6366 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6369 radius = atof(Cmd_Argv(2));
6371 else if (!strcmp(Cmd_Argv(1), "colorscale"))
6373 if (Cmd_Argc() == 3)
6375 double scale = atof(Cmd_Argv(2));
6382 if (Cmd_Argc() != 5)
6384 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
6387 color[0] *= atof(Cmd_Argv(2));
6388 color[1] *= atof(Cmd_Argv(3));
6389 color[2] *= atof(Cmd_Argv(4));
6392 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
6394 if (Cmd_Argc() != 3)
6396 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6399 radius *= atof(Cmd_Argv(2));
6401 else if (!strcmp(Cmd_Argv(1), "style"))
6403 if (Cmd_Argc() != 3)
6405 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6408 style = atoi(Cmd_Argv(2));
6410 else if (!strcmp(Cmd_Argv(1), "cubemap"))
6414 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6417 if (Cmd_Argc() == 3)
6418 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
6422 else if (!strcmp(Cmd_Argv(1), "shadows"))
6424 if (Cmd_Argc() != 3)
6426 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6429 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6431 else if (!strcmp(Cmd_Argv(1), "corona"))
6433 if (Cmd_Argc() != 3)
6435 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6438 corona = atof(Cmd_Argv(2));
6440 else if (!strcmp(Cmd_Argv(1), "coronasize"))
6442 if (Cmd_Argc() != 3)
6444 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6447 coronasizescale = atof(Cmd_Argv(2));
6449 else if (!strcmp(Cmd_Argv(1), "ambient"))
6451 if (Cmd_Argc() != 3)
6453 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6456 ambientscale = atof(Cmd_Argv(2));
6458 else if (!strcmp(Cmd_Argv(1), "diffuse"))
6460 if (Cmd_Argc() != 3)
6462 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6465 diffusescale = atof(Cmd_Argv(2));
6467 else if (!strcmp(Cmd_Argv(1), "specular"))
6469 if (Cmd_Argc() != 3)
6471 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6474 specularscale = atof(Cmd_Argv(2));
6476 else if (!strcmp(Cmd_Argv(1), "normalmode"))
6478 if (Cmd_Argc() != 3)
6480 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6483 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6485 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
6487 if (Cmd_Argc() != 3)
6489 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6492 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6496 Con_Print("usage: r_editlights_edit [property] [value]\n");
6497 Con_Print("Selected light's properties:\n");
6498 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6499 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6500 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6501 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
6502 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
6503 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
6504 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
6505 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
6506 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
6507 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
6508 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
6509 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
6510 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
6511 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
6514 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
6515 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6518 static void R_Shadow_EditLights_EditAll_f(void)
6521 dlight_t *light, *oldselected;
6524 if (!r_editlights.integer)
6526 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
6530 oldselected = r_shadow_selectedlight;
6531 // EditLights doesn't seem to have a "remove" command or something so:
6532 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6533 for (lightindex = 0;lightindex < range;lightindex++)
6535 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6538 R_Shadow_SelectLight(light);
6539 R_Shadow_EditLights_Edit_f();
6541 // return to old selected (to not mess editing once selection is locked)
6542 R_Shadow_SelectLight(oldselected);
6545 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
6547 int lightnumber, lightcount;
6548 size_t lightindex, range;
6553 if (!r_editlights.integer)
6556 // update cvars so QC can query them
6557 if (r_shadow_selectedlight)
6559 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6560 Cvar_SetQuick(&r_editlights_current_origin, temp);
6561 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6562 Cvar_SetQuick(&r_editlights_current_angles, temp);
6563 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6564 Cvar_SetQuick(&r_editlights_current_color, temp);
6565 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
6566 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
6567 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
6568 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
6569 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
6570 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
6571 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
6572 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
6573 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
6574 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
6575 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
6578 // draw properties on screen
6579 if (!r_editlights_drawproperties.integer)
6581 x = vid_conwidth.value - 240;
6583 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
6586 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6587 for (lightindex = 0;lightindex < range;lightindex++)
6589 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6592 if (light == r_shadow_selectedlight)
6593 lightnumber = (int)lightindex;
6596 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;
6597 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;
6599 if (r_shadow_selectedlight == NULL)
6601 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;
6602 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;
6603 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;
6604 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;
6605 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;
6606 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;
6607 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;
6608 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;
6609 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;
6610 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;
6611 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;
6612 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;
6613 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;
6614 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;
6615 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;
6618 static void R_Shadow_EditLights_ToggleShadow_f(void)
6620 if (!r_editlights.integer)
6622 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6625 if (!r_shadow_selectedlight)
6627 Con_Print("No selected light.\n");
6630 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);
6633 static void R_Shadow_EditLights_ToggleCorona_f(void)
6635 if (!r_editlights.integer)
6637 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6640 if (!r_shadow_selectedlight)
6642 Con_Print("No selected light.\n");
6645 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);
6648 static void R_Shadow_EditLights_Remove_f(void)
6650 if (!r_editlights.integer)
6652 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
6655 if (!r_shadow_selectedlight)
6657 Con_Print("No selected light.\n");
6660 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
6661 r_shadow_selectedlight = NULL;
6664 static void R_Shadow_EditLights_Help_f(void)
6667 "Documentation on r_editlights system:\n"
6669 "r_editlights : enable/disable editing mode\n"
6670 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
6671 "r_editlights_cursorpushback : push back cursor this far from surface\n"
6672 "r_editlights_cursorpushoff : push cursor off surface this far\n"
6673 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
6674 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
6676 "r_editlights_help : this help\n"
6677 "r_editlights_clear : remove all lights\n"
6678 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
6679 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
6680 "r_editlights_save : save to .rtlights file\n"
6681 "r_editlights_spawn : create a light with default settings\n"
6682 "r_editlights_edit command : edit selected light - more documentation below\n"
6683 "r_editlights_remove : remove selected light\n"
6684 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
6685 "r_editlights_importlightentitiesfrommap : reload light entities\n"
6686 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
6688 "origin x y z : set light location\n"
6689 "originx x: set x component of light location\n"
6690 "originy y: set y component of light location\n"
6691 "originz z: set z component of light location\n"
6692 "move x y z : adjust light location\n"
6693 "movex x: adjust x component of light location\n"
6694 "movey y: adjust y component of light location\n"
6695 "movez z: adjust z component of light location\n"
6696 "angles x y z : set light angles\n"
6697 "anglesx x: set x component of light angles\n"
6698 "anglesy y: set y component of light angles\n"
6699 "anglesz z: set z component of light angles\n"
6700 "color r g b : set color of light (can be brighter than 1 1 1)\n"
6701 "radius radius : set radius (size) of light\n"
6702 "colorscale grey : multiply color of light (1 does nothing)\n"
6703 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
6704 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
6705 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
6706 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
6707 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
6708 "cubemap basename : set filter cubemap of light\n"
6709 "shadows 1/0 : turn on/off shadows\n"
6710 "corona n : set corona intensity\n"
6711 "coronasize n : set corona size (0-1)\n"
6712 "ambient n : set ambient intensity (0-1)\n"
6713 "diffuse n : set diffuse intensity (0-1)\n"
6714 "specular n : set specular intensity (0-1)\n"
6715 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6716 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6717 "<nothing> : print light properties to console\n"
6721 static void R_Shadow_EditLights_CopyInfo_f(void)
6723 if (!r_editlights.integer)
6725 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
6728 if (!r_shadow_selectedlight)
6730 Con_Print("No selected light.\n");
6733 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6734 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6735 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6736 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6737 if (r_shadow_selectedlight->cubemapname)
6738 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6740 r_shadow_bufferlight.cubemapname[0] = 0;
6741 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6742 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6743 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6744 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6745 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6746 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6747 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6750 static void R_Shadow_EditLights_PasteInfo_f(void)
6752 if (!r_editlights.integer)
6754 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6757 if (!r_shadow_selectedlight)
6759 Con_Print("No selected light.\n");
6762 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);
6765 static void R_Shadow_EditLights_Lock_f(void)
6767 if (!r_editlights.integer)
6769 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6772 if (r_editlights_lockcursor)
6774 r_editlights_lockcursor = false;
6777 if (!r_shadow_selectedlight)
6779 Con_Print("No selected light to lock on.\n");
6782 r_editlights_lockcursor = true;
6785 static void R_Shadow_EditLights_Init(void)
6787 Cvar_RegisterVariable(&r_editlights);
6788 Cvar_RegisterVariable(&r_editlights_cursordistance);
6789 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6790 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6791 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6792 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6793 Cvar_RegisterVariable(&r_editlights_drawproperties);
6794 Cvar_RegisterVariable(&r_editlights_current_origin);
6795 Cvar_RegisterVariable(&r_editlights_current_angles);
6796 Cvar_RegisterVariable(&r_editlights_current_color);
6797 Cvar_RegisterVariable(&r_editlights_current_radius);
6798 Cvar_RegisterVariable(&r_editlights_current_corona);
6799 Cvar_RegisterVariable(&r_editlights_current_coronasize);
6800 Cvar_RegisterVariable(&r_editlights_current_style);
6801 Cvar_RegisterVariable(&r_editlights_current_shadows);
6802 Cvar_RegisterVariable(&r_editlights_current_cubemap);
6803 Cvar_RegisterVariable(&r_editlights_current_ambient);
6804 Cvar_RegisterVariable(&r_editlights_current_diffuse);
6805 Cvar_RegisterVariable(&r_editlights_current_specular);
6806 Cvar_RegisterVariable(&r_editlights_current_normalmode);
6807 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
6808 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6809 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6810 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)");
6811 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6812 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6813 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6814 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)");
6815 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6816 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6817 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6818 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6819 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6820 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6821 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)");
6822 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6828 =============================================================================
6832 =============================================================================
6835 void R_LightPoint(float *color, const vec3_t p, const int flags)
6837 int i, numlights, flag;
6838 float f, relativepoint[3], dist, dist2, lightradius2;
6843 if (r_fullbright.integer)
6845 VectorSet(color, 1, 1, 1);
6851 if (flags & LP_LIGHTMAP)
6853 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6855 VectorClear(diffuse);
6856 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, color, diffuse, n);
6857 VectorAdd(color, diffuse, color);
6860 VectorSet(color, 1, 1, 1);
6861 color[0] += r_refdef.scene.ambient;
6862 color[1] += r_refdef.scene.ambient;
6863 color[2] += r_refdef.scene.ambient;
6866 if (flags & LP_RTWORLD)
6868 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6869 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6870 for (i = 0; i < numlights; i++)
6872 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6875 light = &dlight->rtlight;
6876 if (!(light->flags & flag))
6879 lightradius2 = light->radius * light->radius;
6880 VectorSubtract(light->shadoworigin, p, relativepoint);
6881 dist2 = VectorLength2(relativepoint);
6882 if (dist2 >= lightradius2)
6884 dist = sqrt(dist2) / light->radius;
6885 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
6888 // todo: add to both ambient and diffuse
6889 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1)
6890 VectorMA(color, f, light->currentcolor, color);
6893 if (flags & LP_DYNLIGHT)
6896 for (i = 0;i < r_refdef.scene.numlights;i++)
6898 light = r_refdef.scene.lights[i];
6900 lightradius2 = light->radius * light->radius;
6901 VectorSubtract(light->shadoworigin, p, relativepoint);
6902 dist2 = VectorLength2(relativepoint);
6903 if (dist2 >= lightradius2)
6905 dist = sqrt(dist2) / light->radius;
6906 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
6909 // todo: add to both ambient and diffuse
6910 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1)
6911 VectorMA(color, f, light->color, color);
6916 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
6918 int i, numlights, flag;
6921 float relativepoint[3];
6930 if (r_fullbright.integer)
6932 VectorSet(ambient, 1, 1, 1);
6933 VectorClear(diffuse);
6934 VectorClear(lightdir);
6938 if (flags == LP_LIGHTMAP)
6940 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6941 VectorClear(diffuse);
6942 VectorClear(lightdir);
6943 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6944 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
6946 VectorSet(ambient, 1, 1, 1);
6950 memset(sample, 0, sizeof(sample));
6951 VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6953 if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6956 VectorClear(tempambient);
6958 VectorClear(relativepoint);
6959 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6960 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
6961 VectorScale(color, r_refdef.lightmapintensity, color);
6962 VectorAdd(sample, tempambient, sample);
6963 VectorMA(sample , 0.5f , color, sample );
6964 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6965 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6966 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6967 // calculate a weighted average light direction as well
6968 intensity = VectorLength(color);
6969 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6972 if (flags & LP_RTWORLD)
6974 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6975 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6976 for (i = 0; i < numlights; i++)
6978 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6981 light = &dlight->rtlight;
6982 if (!(light->flags & flag))
6985 lightradius2 = light->radius * light->radius;
6986 VectorSubtract(light->shadoworigin, p, relativepoint);
6987 dist2 = VectorLength2(relativepoint);
6988 if (dist2 >= lightradius2)
6990 dist = sqrt(dist2) / light->radius;
6991 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6992 if (intensity <= 0.0f)
6994 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
6996 // scale down intensity to add to both ambient and diffuse
6997 //intensity *= 0.5f;
6998 VectorNormalize(relativepoint);
6999 VectorScale(light->currentcolor, intensity, color);
7000 VectorMA(sample , 0.5f , color, sample );
7001 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7002 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7003 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7004 // calculate a weighted average light direction as well
7005 intensity *= VectorLength(color);
7006 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7008 // FIXME: sample bouncegrid too!
7011 if (flags & LP_DYNLIGHT)
7014 for (i = 0;i < r_refdef.scene.numlights;i++)
7016 light = r_refdef.scene.lights[i];
7018 lightradius2 = light->radius * light->radius;
7019 VectorSubtract(light->shadoworigin, p, relativepoint);
7020 dist2 = VectorLength2(relativepoint);
7021 if (dist2 >= lightradius2)
7023 dist = sqrt(dist2) / light->radius;
7024 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
7025 if (intensity <= 0.0f)
7027 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
7029 // scale down intensity to add to both ambient and diffuse
7030 //intensity *= 0.5f;
7031 VectorNormalize(relativepoint);
7032 VectorScale(light->currentcolor, intensity, color);
7033 VectorMA(sample , 0.5f , color, sample );
7034 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7035 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7036 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7037 // calculate a weighted average light direction as well
7038 intensity *= VectorLength(color);
7039 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7043 // calculate the direction we'll use to reduce the sample to a directional light source
7044 VectorCopy(sample + 12, dir);
7045 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
7046 VectorNormalize(dir);
7047 // extract the diffuse color along the chosen direction and scale it
7048 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
7049 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
7050 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
7051 // subtract some of diffuse from ambient
7052 VectorMA(sample, -0.333f, diffuse, ambient);
7053 // store the normalized lightdir
7054 VectorCopy(dir, lightdir);