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 extern 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 int r_shadow_shadowmappcf;
200 int r_shadow_shadowmapborder;
201 matrix4x4_t r_shadow_shadowmapmatrix;
202 int r_shadow_lightscissor[4];
203 qboolean r_shadow_usingdeferredprepass;
205 int maxshadowtriangles;
208 int maxshadowvertices;
209 float *shadowvertex3f;
219 unsigned char *shadowsides;
220 int *shadowsideslist;
227 int r_shadow_buffer_numleafpvsbytes;
228 unsigned char *r_shadow_buffer_visitingleafpvs;
229 unsigned char *r_shadow_buffer_leafpvs;
230 int *r_shadow_buffer_leaflist;
232 int r_shadow_buffer_numsurfacepvsbytes;
233 unsigned char *r_shadow_buffer_surfacepvs;
234 int *r_shadow_buffer_surfacelist;
235 unsigned char *r_shadow_buffer_surfacesides;
237 int r_shadow_buffer_numshadowtrispvsbytes;
238 unsigned char *r_shadow_buffer_shadowtrispvs;
239 int r_shadow_buffer_numlighttrispvsbytes;
240 unsigned char *r_shadow_buffer_lighttrispvs;
242 rtexturepool_t *r_shadow_texturepool;
243 rtexture_t *r_shadow_attenuationgradienttexture;
244 rtexture_t *r_shadow_attenuation2dtexture;
245 rtexture_t *r_shadow_attenuation3dtexture;
246 skinframe_t *r_shadow_lightcorona;
247 rtexture_t *r_shadow_shadowmap2dtexture;
248 rtexture_t *r_shadow_shadowmap2dcolortexture;
249 rtexture_t *r_shadow_shadowmapvsdcttexture;
250 int r_shadow_shadowmapsize; // changes for each light based on distance
251 int r_shadow_shadowmaplod; // changes for each light based on distance
253 GLuint r_shadow_prepassgeometryfbo;
254 GLuint r_shadow_prepasslightingdiffusespecularfbo;
255 GLuint r_shadow_prepasslightingdiffusefbo;
256 int r_shadow_prepass_width;
257 int r_shadow_prepass_height;
258 rtexture_t *r_shadow_prepassgeometrydepthtexture;
259 rtexture_t *r_shadow_prepassgeometrydepthcolortexture;
260 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
261 rtexture_t *r_shadow_prepasslightingdiffusetexture;
262 rtexture_t *r_shadow_prepasslightingspeculartexture;
264 // lights are reloaded when this changes
265 char r_shadow_mapname[MAX_QPATH];
267 // used only for light filters (cubemaps)
268 rtexturepool_t *r_shadow_filters_texturepool;
270 static const GLenum r_shadow_prepasslightingdrawbuffers[2] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
272 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"};
273 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"};
274 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
275 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"};
276 cvar_t r_shadow_deferred_8bitrange = {CVAR_SAVE, "r_shadow_deferred_8bitrange", "2", "dynamic range of image-based lighting when using 32bit color (does not apply to fp)"};
277 //cvar_t r_shadow_deferred_fp = {CVAR_SAVE, "r_shadow_deferred_fp", "0", "use 16bit (1) or 32bit (2) floating point for accumulation of image-based lighting"};
278 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)"};
279 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
280 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)"};
281 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"};
282 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
283 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
284 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
285 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
286 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
287 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
288 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
289 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
290 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
291 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)"};
292 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
293 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
294 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
295 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
296 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)"};
297 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"};
298 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
299 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
300 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"};
301 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)"};
302 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
303 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)"};
304 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "0", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"};
305 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)"};
306 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
307 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
308 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
309 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
310 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"};
311 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
312 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
313 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
314 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
315 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
316 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
317 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
318 cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
319 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
320 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)"};
321 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)"};
322 cvar_t r_shadow_particletrace = {CVAR_SAVE, "r_shadow_particletrace", "0", "perform particle tracing for indirect lighting (Global Illumination / radiosity), requires r_shadow_deferred 1, requires r_shadow_realtime_world 1, EXTREMELY SLOW"};
323 cvar_t r_shadow_particletrace_intensity = {CVAR_SAVE, "r_shadow_particletrace_intensity", "128", "overall brightness of particle traced radiosity"};
324 cvar_t r_shadow_particletrace_size = {CVAR_SAVE, "r_shadow_particletrace_size", "32", "particles produce bounce lights of this radius"};
325 cvar_t r_shadow_particletrace_radiusscale = {CVAR_SAVE, "r_shadow_particletrace_radiusscale", "1", "particles stop at this fraction of light radius"};
326 cvar_t r_shadow_particletrace_maxbounce = {CVAR_SAVE, "r_shadow_particletrace_maxbounce", "1", "maximum number of bounces for a particle (minimum is 1)"};
327 cvar_t r_shadow_particletrace_bounceintensity = {CVAR_SAVE, "r_shadow_particletrace_bounceintensity", "1", "amount of energy carried over after each bounce"};
328 cvar_t r_shadow_particletrace_particlespacing = {CVAR_SAVE, "r_shadow_particletrace_particlespacing", "0.25", "overlap setting in terms of particle size, this affects how many particles are used"};
329 cvar_t r_shadow_particletrace_updatepercentage = {CVAR_SAVE, "r_shadow_particletrace_updatepercentage", "0.01", "update this fraction of the particles of a light each frame (0 = best performance)"};
330 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, requires r_shadow_realtime_world 1"};
331 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"};
332 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"};
333 cvar_t r_shadow_bouncegrid_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
334 cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "1", "overall brightness of bouncegrid texture"};
335 cvar_t r_shadow_bouncegrid_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_lightradiusscale", "2", "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", "16", "maximum number of bounces for a particle (minimum is 1)"};
337 cvar_t r_shadow_bouncegrid_particlebounceintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particlebounceintensity", "1", "amount of energy carried over after each bounce"};
338 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "16", "brightness of particles contributing to bouncegrid texture"};
339 cvar_t r_shadow_bouncegrid_particlespacing = {CVAR_SAVE, "r_shadow_bouncegrid_particlespacing", "32", "emit one particle per this many units (squared) of radius (squared)"};
340 cvar_t r_shadow_bouncegrid_spacingx = {CVAR_SAVE, "r_shadow_bouncegrid_spacingx", "64", "unit size of bouncegrid pixel on X axis"};
341 cvar_t r_shadow_bouncegrid_spacingy = {CVAR_SAVE, "r_shadow_bouncegrid_spacingy", "64", "unit size of bouncegrid pixel on Y axis"};
342 cvar_t r_shadow_bouncegrid_spacingz = {CVAR_SAVE, "r_shadow_bouncegrid_spacingz", "64", "unit size of bouncegrid pixel on Z axis"};
343 cvar_t r_shadow_bouncegrid_stablerandom = {CVAR_SAVE, "r_shadow_bouncegrid_stablerandom", "1", "make particle distribution consistent from frame to frame"};
344 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"};
345 cvar_t r_shadow_bouncegrid_x = {CVAR_SAVE, "r_shadow_bouncegrid_x", "64", "maximum texture size of bouncegrid on X axis"};
346 cvar_t r_shadow_bouncegrid_y = {CVAR_SAVE, "r_shadow_bouncegrid_y", "64", "maximum texture size of bouncegrid on Y axis"};
347 cvar_t r_shadow_bouncegrid_z = {CVAR_SAVE, "r_shadow_bouncegrid_z", "32", "maximum texture size of bouncegrid on Z axis"};
348 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
349 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"};
350 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
351 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
352 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
353 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
354 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
355 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
356 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
357 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
358 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
359 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
361 rtexture_t *r_shadow_bouncegridtexture;
362 matrix4x4_t r_shadow_bouncegridmatrix;
363 vec_t r_shadow_bouncegridintensity;
364 static double r_shadow_bouncegridtime;
365 static int r_shadow_bouncegridresolution[3];
367 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
368 #define ATTENTABLESIZE 256
369 // 1D gradient, 2D circle and 3D sphere attenuation textures
370 #define ATTEN1DSIZE 32
371 #define ATTEN2DSIZE 64
372 #define ATTEN3DSIZE 32
374 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
375 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
376 static float r_shadow_attentable[ATTENTABLESIZE+1];
378 rtlight_t *r_shadow_compilingrtlight;
379 static memexpandablearray_t r_shadow_worldlightsarray;
380 dlight_t *r_shadow_selectedlight;
381 dlight_t r_shadow_bufferlight;
382 vec3_t r_editlights_cursorlocation;
383 qboolean r_editlights_lockcursor;
385 extern int con_vislines;
387 void R_Shadow_UncompileWorldLights(void);
388 void R_Shadow_ClearWorldLights(void);
389 void R_Shadow_SaveWorldLights(void);
390 void R_Shadow_LoadWorldLights(void);
391 void R_Shadow_LoadLightsFile(void);
392 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
393 void R_Shadow_EditLights_Reload_f(void);
394 void R_Shadow_ValidateCvars(void);
395 static void R_Shadow_MakeTextures(void);
397 #define EDLIGHTSPRSIZE 8
398 skinframe_t *r_editlights_sprcursor;
399 skinframe_t *r_editlights_sprlight;
400 skinframe_t *r_editlights_sprnoshadowlight;
401 skinframe_t *r_editlights_sprcubemaplight;
402 skinframe_t *r_editlights_sprcubemapnoshadowlight;
403 skinframe_t *r_editlights_sprselection;
405 void R_Shadow_SetShadowMode(void)
407 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
408 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
409 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
410 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
411 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
412 r_shadow_shadowmaplod = -1;
413 r_shadow_shadowmapsize = 0;
414 r_shadow_shadowmapsampler = false;
415 r_shadow_shadowmappcf = 0;
416 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
417 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
419 switch(vid.renderpath)
421 case RENDERPATH_GL20:
422 if(r_shadow_shadowmapfilterquality < 0)
424 if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
425 r_shadow_shadowmappcf = 1;
426 else if(strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD"))
428 r_shadow_shadowmapsampler = vid.support.arb_shadow;
429 r_shadow_shadowmappcf = 1;
431 else if(strstr(gl_vendor, "ATI"))
432 r_shadow_shadowmappcf = 1;
434 r_shadow_shadowmapsampler = vid.support.arb_shadow;
438 switch (r_shadow_shadowmapfilterquality)
441 r_shadow_shadowmapsampler = vid.support.arb_shadow;
444 r_shadow_shadowmapsampler = vid.support.arb_shadow;
445 r_shadow_shadowmappcf = 1;
448 r_shadow_shadowmappcf = 1;
451 r_shadow_shadowmappcf = 2;
455 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
457 case RENDERPATH_D3D9:
458 case RENDERPATH_D3D10:
459 case RENDERPATH_D3D11:
460 case RENDERPATH_SOFT:
461 r_shadow_shadowmapsampler = false;
462 r_shadow_shadowmappcf = 1;
463 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
465 case RENDERPATH_GL13:
467 case RENDERPATH_GL11:
469 case RENDERPATH_GLES2:
475 qboolean R_Shadow_ShadowMappingEnabled(void)
477 switch (r_shadow_shadowmode)
479 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
486 void R_Shadow_FreeShadowMaps(void)
488 R_Shadow_SetShadowMode();
490 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
494 if (r_shadow_shadowmap2dtexture)
495 R_FreeTexture(r_shadow_shadowmap2dtexture);
496 r_shadow_shadowmap2dtexture = NULL;
498 if (r_shadow_shadowmap2dcolortexture)
499 R_FreeTexture(r_shadow_shadowmap2dcolortexture);
500 r_shadow_shadowmap2dcolortexture = NULL;
502 if (r_shadow_shadowmapvsdcttexture)
503 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
504 r_shadow_shadowmapvsdcttexture = NULL;
507 void r_shadow_start(void)
509 // allocate vertex processing arrays
510 r_shadow_bouncegridtexture = NULL;
511 r_shadow_attenuationgradienttexture = NULL;
512 r_shadow_attenuation2dtexture = NULL;
513 r_shadow_attenuation3dtexture = NULL;
514 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
515 r_shadow_shadowmap2dtexture = NULL;
516 r_shadow_shadowmap2dcolortexture = NULL;
517 r_shadow_shadowmapvsdcttexture = NULL;
518 r_shadow_shadowmapmaxsize = 0;
519 r_shadow_shadowmapsize = 0;
520 r_shadow_shadowmaplod = 0;
521 r_shadow_shadowmapfilterquality = -1;
522 r_shadow_shadowmapdepthbits = 0;
523 r_shadow_shadowmapvsdct = false;
524 r_shadow_shadowmapsampler = false;
525 r_shadow_shadowmappcf = 0;
528 R_Shadow_FreeShadowMaps();
530 r_shadow_texturepool = NULL;
531 r_shadow_filters_texturepool = NULL;
532 R_Shadow_ValidateCvars();
533 R_Shadow_MakeTextures();
534 maxshadowtriangles = 0;
535 shadowelements = NULL;
536 maxshadowvertices = 0;
537 shadowvertex3f = NULL;
545 shadowmarklist = NULL;
550 shadowsideslist = NULL;
551 r_shadow_buffer_numleafpvsbytes = 0;
552 r_shadow_buffer_visitingleafpvs = NULL;
553 r_shadow_buffer_leafpvs = NULL;
554 r_shadow_buffer_leaflist = NULL;
555 r_shadow_buffer_numsurfacepvsbytes = 0;
556 r_shadow_buffer_surfacepvs = NULL;
557 r_shadow_buffer_surfacelist = NULL;
558 r_shadow_buffer_surfacesides = NULL;
559 r_shadow_buffer_numshadowtrispvsbytes = 0;
560 r_shadow_buffer_shadowtrispvs = NULL;
561 r_shadow_buffer_numlighttrispvsbytes = 0;
562 r_shadow_buffer_lighttrispvs = NULL;
564 r_shadow_usingdeferredprepass = false;
565 r_shadow_prepass_width = r_shadow_prepass_height = 0;
568 static void R_Shadow_FreeDeferred(void);
569 void r_shadow_shutdown(void)
572 R_Shadow_UncompileWorldLights();
574 R_Shadow_FreeShadowMaps();
576 r_shadow_usingdeferredprepass = false;
577 if (r_shadow_prepass_width)
578 R_Shadow_FreeDeferred();
579 r_shadow_prepass_width = r_shadow_prepass_height = 0;
582 r_shadow_bouncegridtexture = NULL;
583 r_shadow_attenuationgradienttexture = NULL;
584 r_shadow_attenuation2dtexture = NULL;
585 r_shadow_attenuation3dtexture = NULL;
586 R_FreeTexturePool(&r_shadow_texturepool);
587 R_FreeTexturePool(&r_shadow_filters_texturepool);
588 maxshadowtriangles = 0;
590 Mem_Free(shadowelements);
591 shadowelements = NULL;
593 Mem_Free(shadowvertex3f);
594 shadowvertex3f = NULL;
597 Mem_Free(vertexupdate);
600 Mem_Free(vertexremap);
606 Mem_Free(shadowmark);
609 Mem_Free(shadowmarklist);
610 shadowmarklist = NULL;
615 Mem_Free(shadowsides);
618 Mem_Free(shadowsideslist);
619 shadowsideslist = NULL;
620 r_shadow_buffer_numleafpvsbytes = 0;
621 if (r_shadow_buffer_visitingleafpvs)
622 Mem_Free(r_shadow_buffer_visitingleafpvs);
623 r_shadow_buffer_visitingleafpvs = NULL;
624 if (r_shadow_buffer_leafpvs)
625 Mem_Free(r_shadow_buffer_leafpvs);
626 r_shadow_buffer_leafpvs = NULL;
627 if (r_shadow_buffer_leaflist)
628 Mem_Free(r_shadow_buffer_leaflist);
629 r_shadow_buffer_leaflist = NULL;
630 r_shadow_buffer_numsurfacepvsbytes = 0;
631 if (r_shadow_buffer_surfacepvs)
632 Mem_Free(r_shadow_buffer_surfacepvs);
633 r_shadow_buffer_surfacepvs = NULL;
634 if (r_shadow_buffer_surfacelist)
635 Mem_Free(r_shadow_buffer_surfacelist);
636 r_shadow_buffer_surfacelist = NULL;
637 if (r_shadow_buffer_surfacesides)
638 Mem_Free(r_shadow_buffer_surfacesides);
639 r_shadow_buffer_surfacesides = NULL;
640 r_shadow_buffer_numshadowtrispvsbytes = 0;
641 if (r_shadow_buffer_shadowtrispvs)
642 Mem_Free(r_shadow_buffer_shadowtrispvs);
643 r_shadow_buffer_numlighttrispvsbytes = 0;
644 if (r_shadow_buffer_lighttrispvs)
645 Mem_Free(r_shadow_buffer_lighttrispvs);
648 void r_shadow_newmap(void)
650 if (r_shadow_bouncegridtexture) R_FreeTexture(r_shadow_bouncegridtexture);r_shadow_bouncegridtexture = NULL;
651 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
652 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
653 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
654 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
655 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
656 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
657 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
658 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
659 R_Shadow_EditLights_Reload_f();
662 void R_Shadow_Init(void)
664 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
665 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
666 Cvar_RegisterVariable(&r_shadow_usebihculling);
667 Cvar_RegisterVariable(&r_shadow_usenormalmap);
668 Cvar_RegisterVariable(&r_shadow_debuglight);
669 Cvar_RegisterVariable(&r_shadow_deferred);
670 Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
671 // Cvar_RegisterVariable(&r_shadow_deferred_fp);
672 Cvar_RegisterVariable(&r_shadow_gloss);
673 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
674 Cvar_RegisterVariable(&r_shadow_glossintensity);
675 Cvar_RegisterVariable(&r_shadow_glossexponent);
676 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
677 Cvar_RegisterVariable(&r_shadow_glossexact);
678 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
679 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
680 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
681 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
682 Cvar_RegisterVariable(&r_shadow_projectdistance);
683 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
684 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
685 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
686 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
687 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
688 Cvar_RegisterVariable(&r_shadow_realtime_world);
689 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
690 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
691 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
692 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
693 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
694 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
695 Cvar_RegisterVariable(&r_shadow_scissor);
696 Cvar_RegisterVariable(&r_shadow_shadowmapping);
697 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
698 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
699 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
700 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
701 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
702 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
703 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
704 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
705 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
706 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
707 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
708 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
709 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
710 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
711 Cvar_RegisterVariable(&r_shadow_polygonfactor);
712 Cvar_RegisterVariable(&r_shadow_polygonoffset);
713 Cvar_RegisterVariable(&r_shadow_texture3d);
714 Cvar_RegisterVariable(&r_shadow_particletrace);
715 Cvar_RegisterVariable(&r_shadow_particletrace_intensity);
716 Cvar_RegisterVariable(&r_shadow_particletrace_size);
717 Cvar_RegisterVariable(&r_shadow_particletrace_radiusscale);
718 Cvar_RegisterVariable(&r_shadow_particletrace_maxbounce);
719 Cvar_RegisterVariable(&r_shadow_particletrace_bounceintensity);
720 Cvar_RegisterVariable(&r_shadow_particletrace_particlespacing);
721 Cvar_RegisterVariable(&r_shadow_particletrace_updatepercentage);
722 Cvar_RegisterVariable(&r_shadow_bouncegrid);
723 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
724 Cvar_RegisterVariable(&r_shadow_bouncegrid_dlightparticlemultiplier);
725 Cvar_RegisterVariable(&r_shadow_bouncegrid_hitmodels);
726 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
727 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightradiusscale);
728 Cvar_RegisterVariable(&r_shadow_bouncegrid_maxbounce);
729 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
730 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
731 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlespacing);
732 Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingx);
733 Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingy);
734 Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingz);
735 Cvar_RegisterVariable(&r_shadow_bouncegrid_stablerandom);
736 Cvar_RegisterVariable(&r_shadow_bouncegrid_updateinterval);
737 Cvar_RegisterVariable(&r_shadow_bouncegrid_x);
738 Cvar_RegisterVariable(&r_shadow_bouncegrid_y);
739 Cvar_RegisterVariable(&r_shadow_bouncegrid_z);
740 Cvar_RegisterVariable(&r_coronas);
741 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
742 Cvar_RegisterVariable(&r_coronas_occlusionquery);
743 Cvar_RegisterVariable(&gl_flashblend);
744 Cvar_RegisterVariable(&gl_ext_separatestencil);
745 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
746 R_Shadow_EditLights_Init();
747 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
748 maxshadowtriangles = 0;
749 shadowelements = NULL;
750 maxshadowvertices = 0;
751 shadowvertex3f = NULL;
759 shadowmarklist = NULL;
764 shadowsideslist = NULL;
765 r_shadow_buffer_numleafpvsbytes = 0;
766 r_shadow_buffer_visitingleafpvs = NULL;
767 r_shadow_buffer_leafpvs = NULL;
768 r_shadow_buffer_leaflist = NULL;
769 r_shadow_buffer_numsurfacepvsbytes = 0;
770 r_shadow_buffer_surfacepvs = NULL;
771 r_shadow_buffer_surfacelist = NULL;
772 r_shadow_buffer_surfacesides = NULL;
773 r_shadow_buffer_shadowtrispvs = NULL;
774 r_shadow_buffer_lighttrispvs = NULL;
775 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
778 matrix4x4_t matrix_attenuationxyz =
781 {0.5, 0.0, 0.0, 0.5},
782 {0.0, 0.5, 0.0, 0.5},
783 {0.0, 0.0, 0.5, 0.5},
788 matrix4x4_t matrix_attenuationz =
791 {0.0, 0.0, 0.5, 0.5},
792 {0.0, 0.0, 0.0, 0.5},
793 {0.0, 0.0, 0.0, 0.5},
798 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
800 numvertices = ((numvertices + 255) & ~255) * vertscale;
801 numtriangles = ((numtriangles + 255) & ~255) * triscale;
802 // make sure shadowelements is big enough for this volume
803 if (maxshadowtriangles < numtriangles)
805 maxshadowtriangles = numtriangles;
807 Mem_Free(shadowelements);
808 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
810 // make sure shadowvertex3f is big enough for this volume
811 if (maxshadowvertices < numvertices)
813 maxshadowvertices = numvertices;
815 Mem_Free(shadowvertex3f);
816 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
820 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
822 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
823 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
824 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
825 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
826 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
828 if (r_shadow_buffer_visitingleafpvs)
829 Mem_Free(r_shadow_buffer_visitingleafpvs);
830 if (r_shadow_buffer_leafpvs)
831 Mem_Free(r_shadow_buffer_leafpvs);
832 if (r_shadow_buffer_leaflist)
833 Mem_Free(r_shadow_buffer_leaflist);
834 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
835 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
836 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
837 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
839 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
841 if (r_shadow_buffer_surfacepvs)
842 Mem_Free(r_shadow_buffer_surfacepvs);
843 if (r_shadow_buffer_surfacelist)
844 Mem_Free(r_shadow_buffer_surfacelist);
845 if (r_shadow_buffer_surfacesides)
846 Mem_Free(r_shadow_buffer_surfacesides);
847 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
848 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
849 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
850 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
852 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
854 if (r_shadow_buffer_shadowtrispvs)
855 Mem_Free(r_shadow_buffer_shadowtrispvs);
856 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
857 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
859 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
861 if (r_shadow_buffer_lighttrispvs)
862 Mem_Free(r_shadow_buffer_lighttrispvs);
863 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
864 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
868 void R_Shadow_PrepareShadowMark(int numtris)
870 // make sure shadowmark is big enough for this volume
871 if (maxshadowmark < numtris)
873 maxshadowmark = numtris;
875 Mem_Free(shadowmark);
877 Mem_Free(shadowmarklist);
878 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
879 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
883 // if shadowmarkcount wrapped we clear the array and adjust accordingly
884 if (shadowmarkcount == 0)
887 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
892 void R_Shadow_PrepareShadowSides(int numtris)
894 if (maxshadowsides < numtris)
896 maxshadowsides = numtris;
898 Mem_Free(shadowsides);
900 Mem_Free(shadowsideslist);
901 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
902 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
907 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)
910 int outtriangles = 0, outvertices = 0;
913 float ratio, direction[3], projectvector[3];
915 if (projectdirection)
916 VectorScale(projectdirection, projectdistance, projectvector);
918 VectorClear(projectvector);
920 // create the vertices
921 if (projectdirection)
923 for (i = 0;i < numshadowmarktris;i++)
925 element = inelement3i + shadowmarktris[i] * 3;
926 for (j = 0;j < 3;j++)
928 if (vertexupdate[element[j]] != vertexupdatenum)
930 vertexupdate[element[j]] = vertexupdatenum;
931 vertexremap[element[j]] = outvertices;
932 vertex = invertex3f + element[j] * 3;
933 // project one copy of the vertex according to projectvector
934 VectorCopy(vertex, outvertex3f);
935 VectorAdd(vertex, projectvector, (outvertex3f + 3));
944 for (i = 0;i < numshadowmarktris;i++)
946 element = inelement3i + shadowmarktris[i] * 3;
947 for (j = 0;j < 3;j++)
949 if (vertexupdate[element[j]] != vertexupdatenum)
951 vertexupdate[element[j]] = vertexupdatenum;
952 vertexremap[element[j]] = outvertices;
953 vertex = invertex3f + element[j] * 3;
954 // project one copy of the vertex to the sphere radius of the light
955 // (FIXME: would projecting it to the light box be better?)
956 VectorSubtract(vertex, projectorigin, direction);
957 ratio = projectdistance / VectorLength(direction);
958 VectorCopy(vertex, outvertex3f);
959 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
967 if (r_shadow_frontsidecasting.integer)
969 for (i = 0;i < numshadowmarktris;i++)
971 int remappedelement[3];
973 const int *neighbortriangle;
975 markindex = shadowmarktris[i] * 3;
976 element = inelement3i + markindex;
977 neighbortriangle = inneighbor3i + markindex;
978 // output the front and back triangles
979 outelement3i[0] = vertexremap[element[0]];
980 outelement3i[1] = vertexremap[element[1]];
981 outelement3i[2] = vertexremap[element[2]];
982 outelement3i[3] = vertexremap[element[2]] + 1;
983 outelement3i[4] = vertexremap[element[1]] + 1;
984 outelement3i[5] = vertexremap[element[0]] + 1;
988 // output the sides (facing outward from this triangle)
989 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
991 remappedelement[0] = vertexremap[element[0]];
992 remappedelement[1] = vertexremap[element[1]];
993 outelement3i[0] = remappedelement[1];
994 outelement3i[1] = remappedelement[0];
995 outelement3i[2] = remappedelement[0] + 1;
996 outelement3i[3] = remappedelement[1];
997 outelement3i[4] = remappedelement[0] + 1;
998 outelement3i[5] = remappedelement[1] + 1;
1003 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1005 remappedelement[1] = vertexremap[element[1]];
1006 remappedelement[2] = vertexremap[element[2]];
1007 outelement3i[0] = remappedelement[2];
1008 outelement3i[1] = remappedelement[1];
1009 outelement3i[2] = remappedelement[1] + 1;
1010 outelement3i[3] = remappedelement[2];
1011 outelement3i[4] = remappedelement[1] + 1;
1012 outelement3i[5] = remappedelement[2] + 1;
1017 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1019 remappedelement[0] = vertexremap[element[0]];
1020 remappedelement[2] = vertexremap[element[2]];
1021 outelement3i[0] = remappedelement[0];
1022 outelement3i[1] = remappedelement[2];
1023 outelement3i[2] = remappedelement[2] + 1;
1024 outelement3i[3] = remappedelement[0];
1025 outelement3i[4] = remappedelement[2] + 1;
1026 outelement3i[5] = remappedelement[0] + 1;
1035 for (i = 0;i < numshadowmarktris;i++)
1037 int remappedelement[3];
1039 const int *neighbortriangle;
1041 markindex = shadowmarktris[i] * 3;
1042 element = inelement3i + markindex;
1043 neighbortriangle = inneighbor3i + markindex;
1044 // output the front and back triangles
1045 outelement3i[0] = vertexremap[element[2]];
1046 outelement3i[1] = vertexremap[element[1]];
1047 outelement3i[2] = vertexremap[element[0]];
1048 outelement3i[3] = vertexremap[element[0]] + 1;
1049 outelement3i[4] = vertexremap[element[1]] + 1;
1050 outelement3i[5] = vertexremap[element[2]] + 1;
1054 // output the sides (facing outward from this triangle)
1055 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1057 remappedelement[0] = vertexremap[element[0]];
1058 remappedelement[1] = vertexremap[element[1]];
1059 outelement3i[0] = remappedelement[0];
1060 outelement3i[1] = remappedelement[1];
1061 outelement3i[2] = remappedelement[1] + 1;
1062 outelement3i[3] = remappedelement[0];
1063 outelement3i[4] = remappedelement[1] + 1;
1064 outelement3i[5] = remappedelement[0] + 1;
1069 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1071 remappedelement[1] = vertexremap[element[1]];
1072 remappedelement[2] = vertexremap[element[2]];
1073 outelement3i[0] = remappedelement[1];
1074 outelement3i[1] = remappedelement[2];
1075 outelement3i[2] = remappedelement[2] + 1;
1076 outelement3i[3] = remappedelement[1];
1077 outelement3i[4] = remappedelement[2] + 1;
1078 outelement3i[5] = remappedelement[1] + 1;
1083 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1085 remappedelement[0] = vertexremap[element[0]];
1086 remappedelement[2] = vertexremap[element[2]];
1087 outelement3i[0] = remappedelement[2];
1088 outelement3i[1] = remappedelement[0];
1089 outelement3i[2] = remappedelement[0] + 1;
1090 outelement3i[3] = remappedelement[2];
1091 outelement3i[4] = remappedelement[0] + 1;
1092 outelement3i[5] = remappedelement[2] + 1;
1100 *outnumvertices = outvertices;
1101 return outtriangles;
1104 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)
1107 int outtriangles = 0, outvertices = 0;
1109 const float *vertex;
1110 float ratio, direction[3], projectvector[3];
1113 if (projectdirection)
1114 VectorScale(projectdirection, projectdistance, projectvector);
1116 VectorClear(projectvector);
1118 for (i = 0;i < numshadowmarktris;i++)
1120 int remappedelement[3];
1122 const int *neighbortriangle;
1124 markindex = shadowmarktris[i] * 3;
1125 neighbortriangle = inneighbor3i + markindex;
1126 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1127 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1128 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1129 if (side[0] + side[1] + side[2] == 0)
1133 element = inelement3i + markindex;
1135 // create the vertices
1136 for (j = 0;j < 3;j++)
1138 if (side[j] + side[j+1] == 0)
1141 if (vertexupdate[k] != vertexupdatenum)
1143 vertexupdate[k] = vertexupdatenum;
1144 vertexremap[k] = outvertices;
1145 vertex = invertex3f + k * 3;
1146 VectorCopy(vertex, outvertex3f);
1147 if (projectdirection)
1149 // project one copy of the vertex according to projectvector
1150 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1154 // project one copy of the vertex to the sphere radius of the light
1155 // (FIXME: would projecting it to the light box be better?)
1156 VectorSubtract(vertex, projectorigin, direction);
1157 ratio = projectdistance / VectorLength(direction);
1158 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1165 // output the sides (facing outward from this triangle)
1168 remappedelement[0] = vertexremap[element[0]];
1169 remappedelement[1] = vertexremap[element[1]];
1170 outelement3i[0] = remappedelement[1];
1171 outelement3i[1] = remappedelement[0];
1172 outelement3i[2] = remappedelement[0] + 1;
1173 outelement3i[3] = remappedelement[1];
1174 outelement3i[4] = remappedelement[0] + 1;
1175 outelement3i[5] = remappedelement[1] + 1;
1182 remappedelement[1] = vertexremap[element[1]];
1183 remappedelement[2] = vertexremap[element[2]];
1184 outelement3i[0] = remappedelement[2];
1185 outelement3i[1] = remappedelement[1];
1186 outelement3i[2] = remappedelement[1] + 1;
1187 outelement3i[3] = remappedelement[2];
1188 outelement3i[4] = remappedelement[1] + 1;
1189 outelement3i[5] = remappedelement[2] + 1;
1196 remappedelement[0] = vertexremap[element[0]];
1197 remappedelement[2] = vertexremap[element[2]];
1198 outelement3i[0] = remappedelement[0];
1199 outelement3i[1] = remappedelement[2];
1200 outelement3i[2] = remappedelement[2] + 1;
1201 outelement3i[3] = remappedelement[0];
1202 outelement3i[4] = remappedelement[2] + 1;
1203 outelement3i[5] = remappedelement[0] + 1;
1210 *outnumvertices = outvertices;
1211 return outtriangles;
1214 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)
1220 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1222 tend = firsttriangle + numtris;
1223 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1225 // surface box entirely inside light box, no box cull
1226 if (projectdirection)
1228 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1230 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1231 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1232 shadowmarklist[numshadowmark++] = t;
1237 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1238 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1239 shadowmarklist[numshadowmark++] = t;
1244 // surface box not entirely inside light box, cull each triangle
1245 if (projectdirection)
1247 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1249 v[0] = invertex3f + e[0] * 3;
1250 v[1] = invertex3f + e[1] * 3;
1251 v[2] = invertex3f + e[2] * 3;
1252 TriangleNormal(v[0], v[1], v[2], normal);
1253 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1254 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1255 shadowmarklist[numshadowmark++] = t;
1260 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1262 v[0] = invertex3f + e[0] * 3;
1263 v[1] = invertex3f + e[1] * 3;
1264 v[2] = invertex3f + e[2] * 3;
1265 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1266 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1267 shadowmarklist[numshadowmark++] = t;
1273 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1278 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1280 // check if the shadow volume intersects the near plane
1282 // a ray between the eye and light origin may intersect the caster,
1283 // indicating that the shadow may touch the eye location, however we must
1284 // test the near plane (a polygon), not merely the eye location, so it is
1285 // easiest to enlarge the caster bounding shape slightly for this.
1291 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)
1293 int i, tris, outverts;
1294 if (projectdistance < 0.1)
1296 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1299 if (!numverts || !nummarktris)
1301 // make sure shadowelements is big enough for this volume
1302 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1303 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1305 if (maxvertexupdate < numverts)
1307 maxvertexupdate = numverts;
1309 Mem_Free(vertexupdate);
1311 Mem_Free(vertexremap);
1312 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1313 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1314 vertexupdatenum = 0;
1317 if (vertexupdatenum == 0)
1319 vertexupdatenum = 1;
1320 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1321 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1324 for (i = 0;i < nummarktris;i++)
1325 shadowmark[marktris[i]] = shadowmarkcount;
1327 if (r_shadow_compilingrtlight)
1329 // if we're compiling an rtlight, capture the mesh
1330 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1331 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1332 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1333 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1335 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1337 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1338 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1339 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1343 // decide which type of shadow to generate and set stencil mode
1344 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1345 // generate the sides or a solid volume, depending on type
1346 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1347 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1349 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1350 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1351 r_refdef.stats.lights_shadowtriangles += tris;
1352 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1354 // increment stencil if frontface is infront of depthbuffer
1355 GL_CullFace(r_refdef.view.cullface_front);
1356 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1357 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1358 // decrement stencil if backface is infront of depthbuffer
1359 GL_CullFace(r_refdef.view.cullface_back);
1360 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1362 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1364 // decrement stencil if backface is behind depthbuffer
1365 GL_CullFace(r_refdef.view.cullface_front);
1366 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1367 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1368 // increment stencil if frontface is behind depthbuffer
1369 GL_CullFace(r_refdef.view.cullface_back);
1370 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1372 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1373 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1377 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1379 // p1, p2, p3 are in the cubemap's local coordinate system
1380 // bias = border/(size - border)
1383 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1384 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1385 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1386 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1388 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1389 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1390 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1391 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1393 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1394 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1395 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1397 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1398 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1399 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1400 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1402 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1403 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1404 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1405 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1407 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1408 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1409 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1411 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1412 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1413 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1414 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1416 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1417 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1418 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1419 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1421 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1422 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1423 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1428 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1430 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1431 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1434 VectorSubtract(maxs, mins, radius);
1435 VectorScale(radius, 0.5f, radius);
1436 VectorAdd(mins, radius, center);
1437 Matrix4x4_Transform(worldtolight, center, lightcenter);
1438 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1439 VectorSubtract(lightcenter, lightradius, pmin);
1440 VectorAdd(lightcenter, lightradius, pmax);
1442 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1443 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1444 if(ap1 > bias*an1 && ap2 > bias*an2)
1446 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1447 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1448 if(an1 > bias*ap1 && an2 > bias*ap2)
1450 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1451 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1453 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1454 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1455 if(ap1 > bias*an1 && ap2 > bias*an2)
1457 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1458 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1459 if(an1 > bias*ap1 && an2 > bias*ap2)
1461 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1462 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1464 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1465 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1466 if(ap1 > bias*an1 && ap2 > bias*an2)
1468 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1469 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1470 if(an1 > bias*ap1 && an2 > bias*ap2)
1472 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1473 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1478 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1480 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1482 // p is in the cubemap's local coordinate system
1483 // bias = border/(size - border)
1484 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1485 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1486 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1488 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1489 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1490 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1491 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1492 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1493 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1497 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1501 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1502 float scale = (size - 2*border)/size, len;
1503 float bias = border / (float)(size - border), dp, dn, ap, an;
1504 // check if cone enclosing side would cross frustum plane
1505 scale = 2 / (scale*scale + 2);
1506 for (i = 0;i < 5;i++)
1508 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1510 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1511 len = scale*VectorLength2(n);
1512 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1513 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1514 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1516 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1518 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1519 len = scale*VectorLength(n);
1520 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1521 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1522 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1524 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1525 // check if frustum corners/origin cross plane sides
1527 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1528 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1529 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1530 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1531 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1532 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1533 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1534 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1535 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1536 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1537 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1538 for (i = 0;i < 4;i++)
1540 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1541 VectorSubtract(n, p, n);
1542 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1543 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1544 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1545 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1546 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1547 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1548 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1549 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1550 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1553 // finite version, assumes corners are a finite distance from origin dependent on far plane
1554 for (i = 0;i < 5;i++)
1556 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1557 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1558 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1559 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1560 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1561 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1562 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1563 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1564 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1565 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1568 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1571 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)
1579 int mask, surfacemask = 0;
1580 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1582 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1583 tend = firsttriangle + numtris;
1584 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1586 // surface box entirely inside light box, no box cull
1587 if (projectdirection)
1589 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1591 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1592 TriangleNormal(v[0], v[1], v[2], normal);
1593 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1595 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1596 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1597 surfacemask |= mask;
1600 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;
1601 shadowsides[numshadowsides] = mask;
1602 shadowsideslist[numshadowsides++] = t;
1609 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1611 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1612 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1614 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1615 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1616 surfacemask |= mask;
1619 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;
1620 shadowsides[numshadowsides] = mask;
1621 shadowsideslist[numshadowsides++] = t;
1629 // surface box not entirely inside light box, cull each triangle
1630 if (projectdirection)
1632 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1634 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1635 TriangleNormal(v[0], v[1], v[2], normal);
1636 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1637 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1639 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1640 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1641 surfacemask |= mask;
1644 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;
1645 shadowsides[numshadowsides] = mask;
1646 shadowsideslist[numshadowsides++] = t;
1653 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1655 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1656 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1657 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1659 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1660 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1661 surfacemask |= mask;
1664 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;
1665 shadowsides[numshadowsides] = mask;
1666 shadowsideslist[numshadowsides++] = t;
1675 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)
1677 int i, j, outtriangles = 0;
1678 int *outelement3i[6];
1679 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1681 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1682 // make sure shadowelements is big enough for this mesh
1683 if (maxshadowtriangles < outtriangles)
1684 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1686 // compute the offset and size of the separate index lists for each cubemap side
1688 for (i = 0;i < 6;i++)
1690 outelement3i[i] = shadowelements + outtriangles * 3;
1691 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1692 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1693 outtriangles += sidetotals[i];
1696 // gather up the (sparse) triangles into separate index lists for each cubemap side
1697 for (i = 0;i < numsidetris;i++)
1699 const int *element = elements + sidetris[i] * 3;
1700 for (j = 0;j < 6;j++)
1702 if (sides[i] & (1 << j))
1704 outelement3i[j][0] = element[0];
1705 outelement3i[j][1] = element[1];
1706 outelement3i[j][2] = element[2];
1707 outelement3i[j] += 3;
1712 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1715 static void R_Shadow_MakeTextures_MakeCorona(void)
1719 unsigned char pixels[32][32][4];
1720 for (y = 0;y < 32;y++)
1722 dy = (y - 15.5f) * (1.0f / 16.0f);
1723 for (x = 0;x < 32;x++)
1725 dx = (x - 15.5f) * (1.0f / 16.0f);
1726 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1727 a = bound(0, a, 255);
1728 pixels[y][x][0] = a;
1729 pixels[y][x][1] = a;
1730 pixels[y][x][2] = a;
1731 pixels[y][x][3] = 255;
1734 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1737 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1739 float dist = sqrt(x*x+y*y+z*z);
1740 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1741 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1742 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1745 static void R_Shadow_MakeTextures(void)
1748 float intensity, dist;
1750 R_Shadow_FreeShadowMaps();
1751 R_FreeTexturePool(&r_shadow_texturepool);
1752 r_shadow_texturepool = R_AllocTexturePool();
1753 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1754 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1755 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1756 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1757 for (x = 0;x <= ATTENTABLESIZE;x++)
1759 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1760 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1761 r_shadow_attentable[x] = bound(0, intensity, 1);
1763 // 1D gradient texture
1764 for (x = 0;x < ATTEN1DSIZE;x++)
1765 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1766 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1767 // 2D circle texture
1768 for (y = 0;y < ATTEN2DSIZE;y++)
1769 for (x = 0;x < ATTEN2DSIZE;x++)
1770 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);
1771 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1772 // 3D sphere texture
1773 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1775 for (z = 0;z < ATTEN3DSIZE;z++)
1776 for (y = 0;y < ATTEN3DSIZE;y++)
1777 for (x = 0;x < ATTEN3DSIZE;x++)
1778 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));
1779 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);
1782 r_shadow_attenuation3dtexture = NULL;
1785 R_Shadow_MakeTextures_MakeCorona();
1787 // Editor light sprites
1788 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1805 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1806 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1823 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1824 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1841 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1842 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1859 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1860 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1877 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1878 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1895 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1898 void R_Shadow_ValidateCvars(void)
1900 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1901 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1902 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1903 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1904 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1905 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1908 void R_Shadow_RenderMode_Begin(void)
1914 R_Shadow_ValidateCvars();
1916 if (!r_shadow_attenuation2dtexture
1917 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1918 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1919 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1920 R_Shadow_MakeTextures();
1923 R_Mesh_ResetTextureState();
1924 GL_BlendFunc(GL_ONE, GL_ZERO);
1925 GL_DepthRange(0, 1);
1926 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1928 GL_DepthMask(false);
1929 GL_Color(0, 0, 0, 1);
1930 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1932 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1934 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1936 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1937 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1939 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1941 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1942 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1946 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1947 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1950 switch(vid.renderpath)
1952 case RENDERPATH_GL20:
1953 case RENDERPATH_D3D9:
1954 case RENDERPATH_D3D10:
1955 case RENDERPATH_D3D11:
1956 case RENDERPATH_SOFT:
1957 case RENDERPATH_GLES2:
1958 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1960 case RENDERPATH_GL13:
1961 case RENDERPATH_GL11:
1962 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1963 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1964 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1965 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1966 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1967 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1969 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1975 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1976 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1977 r_shadow_drawbuffer = drawbuffer;
1978 r_shadow_readbuffer = readbuffer;
1980 r_shadow_cullface_front = r_refdef.view.cullface_front;
1981 r_shadow_cullface_back = r_refdef.view.cullface_back;
1984 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1986 rsurface.rtlight = rtlight;
1989 void R_Shadow_RenderMode_Reset(void)
1991 R_Mesh_ResetRenderTargets();
1992 R_SetViewport(&r_refdef.view.viewport);
1993 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1994 R_Mesh_ResetTextureState();
1995 GL_DepthRange(0, 1);
1997 GL_DepthMask(false);
1998 GL_DepthFunc(GL_LEQUAL);
1999 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2000 r_refdef.view.cullface_front = r_shadow_cullface_front;
2001 r_refdef.view.cullface_back = r_shadow_cullface_back;
2002 GL_CullFace(r_refdef.view.cullface_back);
2003 GL_Color(1, 1, 1, 1);
2004 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2005 GL_BlendFunc(GL_ONE, GL_ZERO);
2006 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
2007 r_shadow_usingshadowmap2d = false;
2008 r_shadow_usingshadowmaportho = false;
2009 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2012 void R_Shadow_ClearStencil(void)
2014 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2015 r_refdef.stats.lights_clears++;
2018 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2020 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2021 if (r_shadow_rendermode == mode)
2023 R_Shadow_RenderMode_Reset();
2024 GL_DepthFunc(GL_LESS);
2025 GL_ColorMask(0, 0, 0, 0);
2026 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2027 GL_CullFace(GL_NONE);
2028 R_SetupShader_DepthOrShadow();
2029 r_shadow_rendermode = mode;
2034 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2035 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2036 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2038 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2039 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2040 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2045 static void R_Shadow_MakeVSDCT(void)
2047 // maps to a 2x3 texture rectangle with normalized coordinates
2052 // stores abs(dir.xy), offset.xy/2.5
2053 unsigned char data[4*6] =
2055 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2056 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2057 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2058 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2059 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2060 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2062 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2065 static void R_Shadow_MakeShadowMap(int side, int size)
2067 switch (r_shadow_shadowmode)
2069 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2070 if (r_shadow_shadowmap2dtexture) return;
2071 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2072 r_shadow_shadowmap2dcolortexture = NULL;
2073 switch(vid.renderpath)
2076 case RENDERPATH_D3D9:
2077 r_shadow_shadowmap2dcolortexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), NULL, TEXTYPE_BGRA, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2078 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2082 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, NULL, NULL, NULL, NULL);
2090 // render depth into the fbo, do not render color at all
2091 // validate the fbo now
2095 qglDrawBuffer(GL_NONE);CHECKGLERROR
2096 qglReadBuffer(GL_NONE);CHECKGLERROR
2097 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2098 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2100 Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2101 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2102 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2107 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2109 float nearclip, farclip, bias;
2110 r_viewport_t viewport;
2113 float clearcolor[4];
2114 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2116 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2117 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2118 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2119 r_shadow_shadowmapside = side;
2120 r_shadow_shadowmapsize = size;
2122 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2123 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2124 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2125 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2127 // complex unrolled cube approach (more flexible)
2128 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2129 R_Shadow_MakeVSDCT();
2130 if (!r_shadow_shadowmap2dtexture)
2131 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2132 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2133 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2134 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2135 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2137 R_Mesh_ResetTextureState();
2138 R_Mesh_ResetRenderTargets();
2139 R_Shadow_RenderMode_Reset();
2142 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2143 R_SetupShader_DepthOrShadow();
2146 R_SetupShader_ShowDepth();
2147 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2152 R_SetViewport(&viewport);
2153 flipped = (side & 1) ^ (side >> 2);
2154 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2155 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2156 switch(vid.renderpath)
2158 case RENDERPATH_GL11:
2159 case RENDERPATH_GL13:
2160 case RENDERPATH_GL20:
2161 case RENDERPATH_SOFT:
2162 case RENDERPATH_GLES2:
2163 GL_CullFace(r_refdef.view.cullface_back);
2164 // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
2165 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2167 // get tightest scissor rectangle that encloses all viewports in the clear mask
2168 int x1 = clear & 0x15 ? 0 : size;
2169 int x2 = clear & 0x2A ? 2 * size : size;
2170 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2171 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2172 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2173 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2175 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2177 case RENDERPATH_D3D9:
2178 case RENDERPATH_D3D10:
2179 case RENDERPATH_D3D11:
2180 Vector4Set(clearcolor, 1,1,1,1);
2181 // completely different meaning than in OpenGL path
2182 r_shadow_shadowmap_parameters[1] = 0;
2183 r_shadow_shadowmap_parameters[3] = -bias;
2184 // we invert the cull mode because we flip the projection matrix
2185 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2186 GL_CullFace(r_refdef.view.cullface_front);
2187 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2188 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2189 if (r_shadow_shadowmapsampler)
2191 GL_ColorMask(0,0,0,0);
2193 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2197 GL_ColorMask(1,1,1,1);
2199 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2205 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2207 R_Mesh_ResetTextureState();
2208 R_Mesh_ResetRenderTargets();
2211 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2212 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2213 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2214 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2216 R_Shadow_RenderMode_Reset();
2217 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2219 GL_DepthFunc(GL_EQUAL);
2220 // do global setup needed for the chosen lighting mode
2221 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2222 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2223 r_shadow_usingshadowmap2d = shadowmapping;
2224 r_shadow_rendermode = r_shadow_lightingrendermode;
2225 // only draw light where this geometry was already rendered AND the
2226 // stencil is 128 (values other than this mean shadow)
2228 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2230 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2233 static const unsigned short bboxelements[36] =
2243 static const float bboxpoints[8][3] =
2255 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2258 float vertex3f[8*3];
2259 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2260 // do global setup needed for the chosen lighting mode
2261 R_Shadow_RenderMode_Reset();
2262 r_shadow_rendermode = r_shadow_lightingrendermode;
2263 R_EntityMatrix(&identitymatrix);
2264 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2265 // only draw light where this geometry was already rendered AND the
2266 // stencil is 128 (values other than this mean shadow)
2267 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2268 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2270 r_shadow_usingshadowmap2d = shadowmapping;
2272 // render the lighting
2273 R_SetupShader_DeferredLight(rsurface.rtlight);
2274 for (i = 0;i < 8;i++)
2275 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2276 GL_ColorMask(1,1,1,1);
2277 GL_DepthMask(false);
2278 GL_DepthRange(0, 1);
2279 GL_PolygonOffset(0, 0);
2281 GL_DepthFunc(GL_GREATER);
2282 GL_CullFace(r_refdef.view.cullface_back);
2283 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL);
2284 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2287 static void R_Shadow_UpdateBounceGridTexture(void)
2289 #define MAXBOUNCEGRIDPARTICLESPERLIGHT 1048576
2291 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2295 int hitsupercontentsmask;
2303 unsigned char *pixel;
2304 unsigned char *pixels;
2305 unsigned int lightindex;
2307 unsigned int range1;
2308 unsigned int range2;
2309 unsigned int seed = (unsigned int)(realtime * 1000.0f);
2311 vec3_t baseshotcolor;
2323 vec_t lightintensity;
2325 qboolean isstatic = r_shadow_bouncegrid_updateinterval.value > 1.0f;
2327 if (!r_shadow_bouncegrid.integer || !vid.support.ext_texture_3d)
2329 if (r_shadow_bouncegridtexture)
2331 R_FreeTexture(r_shadow_bouncegridtexture);
2332 r_shadow_bouncegridtexture = NULL;
2336 if (r_refdef.scene.worldmodel && isstatic)
2338 VectorSet(spacing, bound(1, r_shadow_bouncegrid_spacingx.value, 512), bound(1, r_shadow_bouncegrid_spacingy.value, 512), bound(1, r_shadow_bouncegrid_spacingz.value, 512));
2339 VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
2340 VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
2341 VectorSubtract(maxs, mins, size);
2342 resolution[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2343 resolution[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2344 resolution[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2345 resolution[0] = min(resolution[0], bound(4, r_shadow_bouncegrid_x.integer, (int)vid.maxtexturesize_3d));
2346 resolution[1] = min(resolution[1], bound(4, r_shadow_bouncegrid_y.integer, (int)vid.maxtexturesize_3d));
2347 resolution[2] = min(resolution[2], bound(4, r_shadow_bouncegrid_z.integer, (int)vid.maxtexturesize_3d));
2348 spacing[0] = size[0] / resolution[0];
2349 spacing[1] = size[1] / resolution[1];
2350 spacing[2] = size[2] / resolution[2];
2351 ispacing[0] = 1.0f / spacing[0];
2352 ispacing[1] = 1.0f / spacing[1];
2353 ispacing[2] = 1.0f / spacing[2];
2357 VectorSet(resolution, bound(4, r_shadow_bouncegrid_x.integer, (int)vid.maxtexturesize_3d), bound(4, r_shadow_bouncegrid_y.integer, (int)vid.maxtexturesize_3d), bound(4, r_shadow_bouncegrid_z.integer, (int)vid.maxtexturesize_3d));
2358 VectorSet(spacing, bound(1, r_shadow_bouncegrid_spacingx.value, 512), bound(1, r_shadow_bouncegrid_spacingy.value, 512), bound(1, r_shadow_bouncegrid_spacingz.value, 512));
2359 VectorMultiply(resolution, spacing, size);
2360 ispacing[0] = 1.0f / spacing[0];
2361 ispacing[1] = 1.0f / spacing[1];
2362 ispacing[2] = 1.0f / spacing[2];
2363 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2364 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2365 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2366 VectorAdd(mins, size, maxs);
2368 memset(m, 0, sizeof(m));
2369 m[0] = 1.0f / size[0];
2370 m[3] = -mins[0] * m[0];
2371 m[5] = 1.0f / size[1];
2372 m[7] = -mins[1] * m[5];
2373 m[10] = 1.0f / size[2];
2374 m[11] = -mins[2] * m[10];
2376 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegridmatrix, m);
2377 r_shadow_bouncegridintensity = r_shadow_bouncegrid_intensity.value;
2378 if (r_shadow_bouncegridtexture && realtime < r_shadow_bouncegridtime + r_shadow_bouncegrid_updateinterval.value && resolution[0] == r_shadow_bouncegridresolution[0] && resolution[1] == r_shadow_bouncegridresolution[1] && resolution[2] == r_shadow_bouncegridresolution[2])
2380 numpixels = resolution[0]*resolution[1]*resolution[2];
2381 // allocate pixels for this update...
2382 pixels = (unsigned char *)Mem_Alloc(r_main_mempool, numpixels * sizeof(unsigned char[4]));
2383 // figure out what we want to interact with
2384 if (r_shadow_bouncegrid_hitmodels.integer)
2385 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK;
2387 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
2388 // iterate world rtlights
2389 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2390 range1 = isstatic ? 0 : r_refdef.scene.numlights;
2391 range2 = range + range1;
2392 for (lightindex = 0;lightindex < range2;lightindex++)
2396 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2397 if (!light || !(light->flags & flag))
2399 rtlight = &light->rtlight;
2400 // when static, we skip styled lights because they tend to change...
2401 if (rtlight->style > 0)
2403 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) * (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1), lightcolor);
2407 if (lightindex < range)
2409 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2410 rtlight = &light->rtlight;
2413 rtlight = r_refdef.scene.lights[lightindex - range];
2414 // draw only visible lights (major speedup)
2417 VectorScale(rtlight->currentcolor, rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale, lightcolor);
2419 if (!VectorLength2(lightcolor))
2421 // shoot particles from this light
2422 // use a calculation for the number of particles that will not
2423 // vary with lightstyle, otherwise we get randomized particle
2424 // distribution, the seeded random is only consistent for a
2425 // consistent number of particles on this light...
2426 radius = rtlight->radius * bound(0.0001f, r_shadow_bouncegrid_lightradiusscale.value, 1024.0f);
2427 s = rtlight->radius / bound(1.0f, r_shadow_bouncegrid_particlespacing.value, 1048576.0f);
2428 lightintensity = VectorLength(rtlight->color) * rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale;
2429 if (lightindex >= range)
2430 lightintensity *= r_shadow_bouncegrid_dlightparticlemultiplier.value;
2431 shootparticles = (int)bound(0, lightintensity * s *s, MAXBOUNCEGRIDPARTICLESPERLIGHT);
2432 if (!shootparticles)
2434 s = 255.0f * r_shadow_bouncegrid_particleintensity.value / shootparticles;
2435 VectorScale(lightcolor, s, baseshotcolor);
2436 maxbounce = bound(1, r_shadow_bouncegrid_maxbounce.integer, 16);
2437 if (VectorLength2(baseshotcolor) < 3.0f)
2439 r_refdef.stats.bouncegrid_lights++;
2440 r_refdef.stats.bouncegrid_particles += shootparticles;
2441 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2443 if (r_shadow_bouncegrid_stablerandom.integer > 0)
2444 seed = lightindex * 11937 + shotparticles;
2445 VectorCopy(baseshotcolor, shotcolor);
2446 VectorCopy(rtlight->shadoworigin, clipstart);
2447 if (r_shadow_bouncegrid_stablerandom.integer < 0)
2448 VectorRandom(clipend);
2450 VectorCheeseRandom(clipend);
2451 VectorMA(clipstart, radius, clipend, clipend);
2452 bouncelimit = 1 + (rtlight->particlecache_updateparticle % maxbounce);
2453 for (bouncecount = 0;;bouncecount++)
2455 r_refdef.stats.bouncegrid_traces++;
2456 cliptrace = CL_TraceLine(clipstart, clipend, r_shadow_bouncegrid_hitmodels.integer ? MOVE_HITMODEL : MOVE_NOMONSTERS, NULL, hitsupercontentsmask, true, false, NULL, true);
2457 //Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask);
2458 if (cliptrace.fraction >= 1.0f)
2460 r_refdef.stats.bouncegrid_hits++;
2461 if (bouncecount > 0)
2463 r_refdef.stats.bouncegrid_splats++;
2464 // figure out which texture pixel this is in
2465 tex[0] = (int)((cliptrace.endpos[0] - mins[0]) * ispacing[0]);
2466 tex[1] = (int)((cliptrace.endpos[1] - mins[1]) * ispacing[1]);
2467 tex[2] = (int)((cliptrace.endpos[2] - mins[2]) * ispacing[2]);
2468 if (tex[0] >= 1 && tex[1] >= 1 && tex[2] >= 1 && tex[0] < resolution[0] - 1 && tex[1] < resolution[1] - 1 && tex[2] < resolution[2] - 1)
2470 // it is within bounds...
2471 pixel = pixels + 4 * ((tex[2]*resolution[1]+tex[1])*resolution[0]+tex[0]);
2472 // add to the pixel color
2473 c[0] = pixel[0] + (int)shotcolor[2];
2474 c[1] = pixel[1] + (int)shotcolor[1];
2475 c[2] = pixel[2] + (int)shotcolor[0];
2476 pixel[0] = (unsigned char)min(c[0], 255);
2477 pixel[1] = (unsigned char)min(c[1], 255);
2478 pixel[2] = (unsigned char)min(c[2], 255);
2482 if (bouncecount >= bouncelimit)
2484 // scale down shot color by bounce intensity and texture color
2485 VectorScale(shotcolor, r_shadow_bouncegrid_particlebounceintensity.value, shotcolor);
2486 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2487 VectorMultiply(shotcolor, rsurface.texture->currentskinframe->avgcolor, shotcolor);
2488 if (VectorLength2(shotcolor) < 3.0f)
2490 r_refdef.stats.bouncegrid_bounces++;
2491 if (r_shadow_bouncegrid_bounceanglediffuse.integer)
2493 // random direction, primarily along plane normal
2494 s = VectorDistance(cliptrace.endpos, clipend);
2495 if (r_shadow_bouncegrid_stablerandom.integer < 0)
2496 VectorRandom(clipend);
2498 VectorCheeseRandom(clipend);
2499 VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
2500 VectorNormalize(clipend);
2501 VectorScale(clipend, s, clipend);
2505 // reflect the remaining portion of the line across plane normal
2506 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2507 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2509 // calculate the new line start and end
2510 VectorCopy(cliptrace.endpos, clipstart);
2511 VectorAdd(clipstart, clipend, clipend);
2515 if (r_shadow_bouncegridtexture && r_shadow_bouncegridresolution[0] == resolution[0] && r_shadow_bouncegridresolution[1] == resolution[1] && r_shadow_bouncegridresolution[2] == resolution[2])
2516 R_UpdateTexture(r_shadow_bouncegridtexture, pixels, 0, 0, 0, resolution[0], resolution[1], resolution[2]);
2519 VectorCopy(resolution, r_shadow_bouncegridresolution);
2520 if (r_shadow_bouncegridtexture)
2521 R_FreeTexture(r_shadow_bouncegridtexture);
2522 r_shadow_bouncegridtexture = R_LoadTexture3D(r_shadow_texturepool, "bouncegrid", resolution[0], resolution[1], resolution[2], pixels, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, 0, NULL);
2525 r_shadow_bouncegridtime = realtime;
2528 #define MAXPARTICLESPERLIGHT 262144
2529 #define MAXLIGHTSPERDRAW 1024
2531 static void R_Shadow_RenderParticlesForLight(rtlight_t *rtlight)
2537 int hitsupercontentsmask;
2540 int shootparticles = 0;
2543 unsigned int seed = 0;
2544 static unsigned short bouncelight_elements[MAXLIGHTSPERDRAW*36];
2545 static float vertex3f[MAXLIGHTSPERDRAW*24];
2546 static float lightorigin4f[MAXLIGHTSPERDRAW*32];
2547 static float color4f[MAXLIGHTSPERDRAW*32];
2548 float scaledpoints[8][3];
2552 rtlight_particle_t *p;
2553 vec_t wantparticles = 0;
2557 vec_t iparticlesize;
2563 vec3_t currentcolor;
2568 if (!rtlight->draw || !rtlight->isstatic || !r_shadow_usingdeferredprepass)
2570 if (r_shadow_particletrace.integer)
2572 radius = rtlight->radius * bound(0.0001f, r_shadow_particletrace_radiusscale.value, 1.0f) - r_shadow_particletrace_size.value;
2573 s = rtlight->radius / bound(1.0f, r_shadow_particletrace_particlespacing.value * r_shadow_particletrace_size.value, 1048576.0f);
2574 wantparticles = s*s;
2575 n = (int)bound(0, wantparticles, MAXPARTICLESPERLIGHT);
2579 shootparticles = (int)(n * r_shadow_particletrace_updatepercentage.value);
2580 if ((n && !rtlight->particlecache_particles) || rtlight->particlecache_maxparticles != n)
2582 if (rtlight->particlecache_particles)
2583 Mem_Free(rtlight->particlecache_particles);
2584 rtlight->particlecache_particles = NULL;
2585 rtlight->particlecache_numparticles = 0;
2586 rtlight->particlecache_maxparticles = n;
2587 rtlight->particlecache_updateparticle = 0;
2588 if (rtlight->particlecache_maxparticles)
2589 rtlight->particlecache_particles = (rtlight_particle_t *)Mem_Alloc(r_main_mempool, rtlight->particlecache_maxparticles * sizeof(*rtlight->particlecache_particles));
2590 shootparticles = n * 16;
2593 if (!rtlight->particlecache_maxparticles)
2596 // if (rtlight->particlecache_numparticles < rtlight->particlecache_maxparticles)
2597 // shootparticles = rtlight->particlecache_maxparticles;
2599 // if (rtlight->particlecache_numparticles >= rtlight->particlecache_maxparticles)
2600 // shootparticles = 0;
2602 maxbounce = bound(1, r_shadow_particletrace_maxbounce.integer, 16);
2603 //r_refdef.stats.lights_bouncelightsupdated += shootparticles;
2604 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2606 seed = rtlight->particlecache_updateparticle;
2607 VectorSet(shotcolor, 1.0f, 1.0f, 1.0f);
2608 VectorCopy(rtlight->shadoworigin, clipstart);
2609 VectorRandom(clipend);
2610 VectorMA(clipstart, radius, clipend, clipend);
2611 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
2612 bouncelimit = 1 + (rtlight->particlecache_updateparticle % maxbounce);
2613 for (bouncecount = 0;;bouncecount++)
2615 cliptrace = CL_TraceLine(clipstart, clipend, MOVE_NOMONSTERS, NULL, hitsupercontentsmask, true, false, NULL, true);
2616 //Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask);
2617 if (cliptrace.fraction >= 1.0f)
2619 if (VectorLength2(shotcolor) < (1.0f / 262144.0f))
2621 if (bouncecount >= bouncelimit)
2623 VectorCopy(cliptrace.endpos, rtlight->particlecache_particles[rtlight->particlecache_updateparticle].origin);
2624 VectorCopy(shotcolor, rtlight->particlecache_particles[rtlight->particlecache_updateparticle].color);
2625 rtlight->particlecache_updateparticle++;
2626 if (rtlight->particlecache_numparticles < rtlight->particlecache_updateparticle)
2627 rtlight->particlecache_numparticles = rtlight->particlecache_updateparticle;
2628 if (rtlight->particlecache_updateparticle >= rtlight->particlecache_maxparticles)
2630 rtlight->particlecache_updateparticle = 0;
2631 shotparticles = shootparticles;
2635 // scale down shot color by bounce intensity and texture color
2636 VectorScale(shotcolor, r_shadow_particletrace_bounceintensity.value, shotcolor);
2637 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2638 VectorMultiply(shotcolor, rsurface.texture->currentskinframe->avgcolor, shotcolor);
2639 // reflect the remaining portion of the line across plane normal
2640 //VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2641 //VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2642 // random direction, primarily along plane normal
2643 s = VectorDistance(cliptrace.endpos, clipend);
2644 VectorRandom(clipend);
2645 VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
2646 VectorNormalize(clipend);
2647 VectorScale(clipend, s, clipend);
2648 // calculate the new line start and end
2649 VectorCopy(cliptrace.endpos, clipstart);
2650 VectorAdd(clipstart, clipend, clipend);
2654 if (!rtlight->particlecache_numparticles)
2657 // render the particles as deferred lights
2658 // do global setup needed for the chosen lighting mode
2659 R_Shadow_RenderMode_Reset();
2660 r_shadow_rendermode = r_shadow_lightingrendermode;
2661 r_shadow_usingshadowmap2d = false;
2662 R_EntityMatrix(&identitymatrix);
2663 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2664 // only draw light where this geometry was already rendered AND the
2665 // stencil is 128 (values other than this mean shadow)
2666 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2667 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
2668 R_SetupShader_DeferredBounceLight();
2669 GL_ColorMask(1,1,1,1);
2670 GL_DepthMask(false);
2671 GL_DepthRange(0, 1);
2672 GL_PolygonOffset(0, 0);
2674 GL_DepthFunc(GL_GREATER);
2675 GL_CullFace(r_refdef.view.cullface_back);
2676 s = r_shadow_particletrace_intensity.value / (float)rtlight->particlecache_numparticles;
2677 VectorScale(rtlight->currentcolor, s, currentcolor);
2678 particlesize = bound(0.0001f, r_shadow_particletrace_size.value, 1024.0f);
2679 iparticlesize = 1.0f / particlesize;
2680 // VectorScale(r_refdef.view.forward, particlesize, offset);
2681 // VectorScale(r_refdef.view.left, -particlesize, right);
2682 // VectorScale(r_refdef.view.up, particlesize, up);
2683 org[3] = iparticlesize;
2686 lo4f = lightorigin4f;
2689 if (!bouncelight_elements[1])
2690 for (i = 0;i < MAXLIGHTSPERDRAW;i++)
2691 for (j = 0;j < 36;j++)
2692 bouncelight_elements[i*36+j] = i*8+bboxelements[j];
2693 for (j = 0;j < 8;j++)
2694 VectorScale(bboxpoints[j], particlesize, scaledpoints[j]);
2695 //r_refdef.stats.lights_bouncelightscounted += rtlight->particlecache_numparticles;
2696 for (j = 0, p = rtlight->particlecache_particles, n = rtlight->particlecache_numparticles;j < n;j++, p++)
2698 VectorCopy(p->origin, org);
2699 // org[3] is set above
2700 VectorMultiply(p->color, currentcolor, color);
2701 // color[3] is set above
2702 VectorAdd(scaledpoints[0], org, v3f + 0);
2703 VectorAdd(scaledpoints[1], org, v3f + 3);
2704 VectorAdd(scaledpoints[2], org, v3f + 6);
2705 VectorAdd(scaledpoints[3], org, v3f + 9);
2706 VectorAdd(scaledpoints[4], org, v3f + 12);
2707 VectorAdd(scaledpoints[5], org, v3f + 15);
2708 VectorAdd(scaledpoints[6], org, v3f + 18);
2709 VectorAdd(scaledpoints[7], org, v3f + 21);
2710 Vector4Copy(org, lo4f + 0);
2711 Vector4Copy(org, lo4f + 4);
2712 Vector4Copy(org, lo4f + 8);
2713 Vector4Copy(org, lo4f + 12);
2714 Vector4Copy(org, lo4f + 16);
2715 Vector4Copy(org, lo4f + 20);
2716 Vector4Copy(org, lo4f + 24);
2717 Vector4Copy(org, lo4f + 28);
2718 Vector4Copy(color, c4f + 0);
2719 Vector4Copy(color, c4f + 4);
2720 Vector4Copy(color, c4f + 8);
2721 Vector4Copy(color, c4f + 12);
2722 Vector4Copy(color, c4f + 16);
2723 Vector4Copy(color, c4f + 20);
2724 Vector4Copy(color, c4f + 24);
2725 Vector4Copy(color, c4f + 28);
2730 if (batchcount >= MAXLIGHTSPERDRAW)
2732 //r_refdef.stats.lights_bouncelightsdrawn += batchcount;
2733 R_Mesh_PrepareVertices_BounceLight_Arrays(batchcount*8, vertex3f, color4f, lightorigin4f);
2734 R_Mesh_Draw(0, batchcount*8, 0, batchcount*12, NULL, NULL, 0, bouncelight_elements, NULL, 0);
2736 lo4f = lightorigin4f;
2743 //r_refdef.stats.lights_bouncelightsdrawn += batchcount;
2744 R_Mesh_PrepareVertices_BounceLight_Arrays(batchcount*8, vertex3f, color4f, lightorigin4f);
2745 R_Mesh_Draw(0, batchcount*8, 0, batchcount*12, NULL, NULL, 0, bouncelight_elements, NULL, 0);
2747 lo4f = lightorigin4f;
2753 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2755 R_Shadow_RenderMode_Reset();
2756 GL_BlendFunc(GL_ONE, GL_ONE);
2757 GL_DepthRange(0, 1);
2758 GL_DepthTest(r_showshadowvolumes.integer < 2);
2759 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2760 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2761 GL_CullFace(GL_NONE);
2762 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2765 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2767 R_Shadow_RenderMode_Reset();
2768 GL_BlendFunc(GL_ONE, GL_ONE);
2769 GL_DepthRange(0, 1);
2770 GL_DepthTest(r_showlighting.integer < 2);
2771 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2773 GL_DepthFunc(GL_EQUAL);
2774 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2775 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2778 void R_Shadow_RenderMode_End(void)
2780 R_Shadow_RenderMode_Reset();
2781 R_Shadow_RenderMode_ActiveLight(NULL);
2783 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2784 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2787 int bboxedges[12][2] =
2806 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2808 if (!r_shadow_scissor.integer)
2810 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2811 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2812 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2813 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2816 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2817 return true; // invisible
2818 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2819 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2820 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2821 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2822 r_refdef.stats.lights_scissored++;
2826 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2829 const float *vertex3f;
2830 const float *normal3f;
2832 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2833 switch (r_shadow_rendermode)
2835 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2836 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2837 if (VectorLength2(diffusecolor) > 0)
2839 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)
2841 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2842 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2843 if ((dot = DotProduct(n, v)) < 0)
2845 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2846 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2849 VectorCopy(ambientcolor, color4f);
2850 if (r_refdef.fogenabled)
2853 f = RSurf_FogVertex(vertex3f);
2854 VectorScale(color4f, f, color4f);
2861 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2863 VectorCopy(ambientcolor, color4f);
2864 if (r_refdef.fogenabled)
2867 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2868 f = RSurf_FogVertex(vertex3f);
2869 VectorScale(color4f + 4*i, f, color4f);
2875 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2876 if (VectorLength2(diffusecolor) > 0)
2878 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)
2880 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2881 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2883 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2884 if ((dot = DotProduct(n, v)) < 0)
2886 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2887 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2888 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2889 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2893 color4f[0] = ambientcolor[0] * distintensity;
2894 color4f[1] = ambientcolor[1] * distintensity;
2895 color4f[2] = ambientcolor[2] * distintensity;
2897 if (r_refdef.fogenabled)
2900 f = RSurf_FogVertex(vertex3f);
2901 VectorScale(color4f, f, color4f);
2905 VectorClear(color4f);
2911 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2913 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2914 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2916 color4f[0] = ambientcolor[0] * distintensity;
2917 color4f[1] = ambientcolor[1] * distintensity;
2918 color4f[2] = ambientcolor[2] * distintensity;
2919 if (r_refdef.fogenabled)
2922 f = RSurf_FogVertex(vertex3f);
2923 VectorScale(color4f, f, color4f);
2927 VectorClear(color4f);
2932 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2933 if (VectorLength2(diffusecolor) > 0)
2935 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)
2937 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2938 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2940 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2941 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2942 if ((dot = DotProduct(n, v)) < 0)
2944 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2945 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2946 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2947 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2951 color4f[0] = ambientcolor[0] * distintensity;
2952 color4f[1] = ambientcolor[1] * distintensity;
2953 color4f[2] = ambientcolor[2] * distintensity;
2955 if (r_refdef.fogenabled)
2958 f = RSurf_FogVertex(vertex3f);
2959 VectorScale(color4f, f, color4f);
2963 VectorClear(color4f);
2969 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2971 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2972 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2974 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2975 color4f[0] = ambientcolor[0] * distintensity;
2976 color4f[1] = ambientcolor[1] * distintensity;
2977 color4f[2] = ambientcolor[2] * distintensity;
2978 if (r_refdef.fogenabled)
2981 f = RSurf_FogVertex(vertex3f);
2982 VectorScale(color4f, f, color4f);
2986 VectorClear(color4f);
2996 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2998 // used to display how many times a surface is lit for level design purposes
2999 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3000 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3004 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
3006 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3007 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
3008 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
3009 GL_DepthFunc(GL_EQUAL);
3011 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
3012 GL_DepthFunc(GL_LEQUAL);
3015 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3022 int newnumtriangles;
3026 int maxtriangles = 4096;
3027 static int newelements[4096*3];
3028 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3029 for (renders = 0;renders < 4;renders++)
3034 newnumtriangles = 0;
3036 // due to low fillrate on the cards this vertex lighting path is
3037 // designed for, we manually cull all triangles that do not
3038 // contain a lit vertex
3039 // this builds batches of triangles from multiple surfaces and
3040 // renders them at once
3041 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3043 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3045 if (newnumtriangles)
3047 newfirstvertex = min(newfirstvertex, e[0]);
3048 newlastvertex = max(newlastvertex, e[0]);
3052 newfirstvertex = e[0];
3053 newlastvertex = e[0];
3055 newfirstvertex = min(newfirstvertex, e[1]);
3056 newlastvertex = max(newlastvertex, e[1]);
3057 newfirstvertex = min(newfirstvertex, e[2]);
3058 newlastvertex = max(newlastvertex, e[2]);
3064 if (newnumtriangles >= maxtriangles)
3066 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3067 newnumtriangles = 0;
3073 if (newnumtriangles >= 1)
3075 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3078 // if we couldn't find any lit triangles, exit early
3081 // now reduce the intensity for the next overbright pass
3082 // we have to clamp to 0 here incase the drivers have improper
3083 // handling of negative colors
3084 // (some old drivers even have improper handling of >1 color)
3086 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3088 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3090 c[0] = max(0, c[0] - 1);
3091 c[1] = max(0, c[1] - 1);
3092 c[2] = max(0, c[2] - 1);
3104 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
3106 // OpenGL 1.1 path (anything)
3107 float ambientcolorbase[3], diffusecolorbase[3];
3108 float ambientcolorpants[3], diffusecolorpants[3];
3109 float ambientcolorshirt[3], diffusecolorshirt[3];
3110 const float *surfacecolor = rsurface.texture->dlightcolor;
3111 const float *surfacepants = rsurface.colormap_pantscolor;
3112 const float *surfaceshirt = rsurface.colormap_shirtcolor;
3113 rtexture_t *basetexture = rsurface.texture->basetexture;
3114 rtexture_t *pantstexture = rsurface.texture->pantstexture;
3115 rtexture_t *shirttexture = rsurface.texture->shirttexture;
3116 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3117 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3118 ambientscale *= 2 * r_refdef.view.colorscale;
3119 diffusescale *= 2 * r_refdef.view.colorscale;
3120 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3121 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3122 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3123 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3124 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3125 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
3126 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3127 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
3128 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3129 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
3130 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
3131 R_Mesh_TexBind(0, basetexture);
3132 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
3133 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
3134 switch(r_shadow_rendermode)
3136 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3137 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
3138 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3139 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3140 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3142 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3143 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
3144 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
3145 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
3146 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3148 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3149 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
3150 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3151 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3152 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3154 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3159 //R_Mesh_TexBind(0, basetexture);
3160 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
3163 R_Mesh_TexBind(0, pantstexture);
3164 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
3168 R_Mesh_TexBind(0, shirttexture);
3169 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
3173 extern cvar_t gl_lightmaps;
3174 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3176 float ambientscale, diffusescale, specularscale;
3178 float lightcolor[3];
3179 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
3180 ambientscale = rsurface.rtlight->ambientscale;
3181 diffusescale = rsurface.rtlight->diffusescale;
3182 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3183 if (!r_shadow_usenormalmap.integer)
3185 ambientscale += 1.0f * diffusescale;
3189 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
3191 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
3194 VectorNegate(lightcolor, lightcolor);
3195 switch(vid.renderpath)
3197 case RENDERPATH_GL11:
3198 case RENDERPATH_GL13:
3199 case RENDERPATH_GL20:
3200 case RENDERPATH_GLES2:
3201 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
3203 case RENDERPATH_D3D9:
3205 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
3208 case RENDERPATH_D3D10:
3209 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3211 case RENDERPATH_D3D11:
3212 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3214 case RENDERPATH_SOFT:
3215 DPSOFTRAST_BlendSubtract(true);
3219 RSurf_SetupDepthAndCulling();
3220 switch (r_shadow_rendermode)
3222 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3223 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3224 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
3226 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3227 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
3229 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3230 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3231 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3232 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3233 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
3236 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3241 switch(vid.renderpath)
3243 case RENDERPATH_GL11:
3244 case RENDERPATH_GL13:
3245 case RENDERPATH_GL20:
3246 case RENDERPATH_GLES2:
3247 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
3249 case RENDERPATH_D3D9:
3251 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
3254 case RENDERPATH_D3D10:
3255 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3257 case RENDERPATH_D3D11:
3258 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3260 case RENDERPATH_SOFT:
3261 DPSOFTRAST_BlendSubtract(false);
3267 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)
3269 matrix4x4_t tempmatrix = *matrix;
3270 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3272 // if this light has been compiled before, free the associated data
3273 R_RTLight_Uncompile(rtlight);
3275 // clear it completely to avoid any lingering data
3276 memset(rtlight, 0, sizeof(*rtlight));
3278 // copy the properties
3279 rtlight->matrix_lighttoworld = tempmatrix;
3280 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3281 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3282 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3283 VectorCopy(color, rtlight->color);
3284 rtlight->cubemapname[0] = 0;
3285 if (cubemapname && cubemapname[0])
3286 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3287 rtlight->shadow = shadow;
3288 rtlight->corona = corona;
3289 rtlight->style = style;
3290 rtlight->isstatic = isstatic;
3291 rtlight->coronasizescale = coronasizescale;
3292 rtlight->ambientscale = ambientscale;
3293 rtlight->diffusescale = diffusescale;
3294 rtlight->specularscale = specularscale;
3295 rtlight->flags = flags;
3297 // compute derived data
3298 //rtlight->cullradius = rtlight->radius;
3299 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3300 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3301 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3302 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3303 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3304 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3305 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3308 // compiles rtlight geometry
3309 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3310 void R_RTLight_Compile(rtlight_t *rtlight)
3313 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3314 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3315 entity_render_t *ent = r_refdef.scene.worldentity;
3316 dp_model_t *model = r_refdef.scene.worldmodel;
3317 unsigned char *data;
3320 // compile the light
3321 rtlight->compiled = true;
3322 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3323 rtlight->static_numleafs = 0;
3324 rtlight->static_numleafpvsbytes = 0;
3325 rtlight->static_leaflist = NULL;
3326 rtlight->static_leafpvs = NULL;
3327 rtlight->static_numsurfaces = 0;
3328 rtlight->static_surfacelist = NULL;
3329 rtlight->static_shadowmap_receivers = 0x3F;
3330 rtlight->static_shadowmap_casters = 0x3F;
3331 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3332 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3333 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3334 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3335 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3336 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3338 if (model && model->GetLightInfo)
3340 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3341 r_shadow_compilingrtlight = rtlight;
3342 R_FrameData_SetMark();
3343 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);
3344 R_FrameData_ReturnToMark();
3345 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3346 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3347 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3348 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3349 rtlight->static_numsurfaces = numsurfaces;
3350 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3351 rtlight->static_numleafs = numleafs;
3352 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3353 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3354 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3355 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3356 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3357 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3358 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3359 if (rtlight->static_numsurfaces)
3360 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3361 if (rtlight->static_numleafs)
3362 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3363 if (rtlight->static_numleafpvsbytes)
3364 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3365 if (rtlight->static_numshadowtrispvsbytes)
3366 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3367 if (rtlight->static_numlighttrispvsbytes)
3368 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3369 R_FrameData_SetMark();
3370 switch (rtlight->shadowmode)
3372 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3373 if (model->CompileShadowMap && rtlight->shadow)
3374 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3377 if (model->CompileShadowVolume && rtlight->shadow)
3378 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3381 R_FrameData_ReturnToMark();
3382 // now we're done compiling the rtlight
3383 r_shadow_compilingrtlight = NULL;
3387 // use smallest available cullradius - box radius or light radius
3388 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3389 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3391 shadowzpasstris = 0;
3392 if (rtlight->static_meshchain_shadow_zpass)
3393 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3394 shadowzpasstris += mesh->numtriangles;
3396 shadowzfailtris = 0;
3397 if (rtlight->static_meshchain_shadow_zfail)
3398 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3399 shadowzfailtris += mesh->numtriangles;
3402 if (rtlight->static_numlighttrispvsbytes)
3403 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3404 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3408 if (rtlight->static_numlighttrispvsbytes)
3409 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3410 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3413 if (developer_extra.integer)
3414 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);
3417 void R_RTLight_Uncompile(rtlight_t *rtlight)
3419 if (rtlight->compiled)
3421 if (rtlight->static_meshchain_shadow_zpass)
3422 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3423 rtlight->static_meshchain_shadow_zpass = NULL;
3424 if (rtlight->static_meshchain_shadow_zfail)
3425 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3426 rtlight->static_meshchain_shadow_zfail = NULL;
3427 if (rtlight->static_meshchain_shadow_shadowmap)
3428 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3429 rtlight->static_meshchain_shadow_shadowmap = NULL;
3430 // these allocations are grouped
3431 if (rtlight->static_surfacelist)
3432 Mem_Free(rtlight->static_surfacelist);
3433 rtlight->static_numleafs = 0;
3434 rtlight->static_numleafpvsbytes = 0;
3435 rtlight->static_leaflist = NULL;
3436 rtlight->static_leafpvs = NULL;
3437 rtlight->static_numsurfaces = 0;
3438 rtlight->static_surfacelist = NULL;
3439 rtlight->static_numshadowtrispvsbytes = 0;
3440 rtlight->static_shadowtrispvs = NULL;
3441 rtlight->static_numlighttrispvsbytes = 0;
3442 rtlight->static_lighttrispvs = NULL;
3443 rtlight->compiled = false;
3447 void R_Shadow_UncompileWorldLights(void)
3451 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3452 for (lightindex = 0;lightindex < range;lightindex++)
3454 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3457 R_RTLight_Uncompile(&light->rtlight);
3461 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3465 // reset the count of frustum planes
3466 // see rtlight->cached_frustumplanes definition for how much this array
3468 rtlight->cached_numfrustumplanes = 0;
3470 // haven't implemented a culling path for ortho rendering
3471 if (!r_refdef.view.useperspective)
3473 // check if the light is on screen and copy the 4 planes if it is
3474 for (i = 0;i < 4;i++)
3475 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3478 for (i = 0;i < 4;i++)
3479 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3484 // generate a deformed frustum that includes the light origin, this is
3485 // used to cull shadow casting surfaces that can not possibly cast a
3486 // shadow onto the visible light-receiving surfaces, which can be a
3489 // if the light origin is onscreen the result will be 4 planes exactly
3490 // if the light origin is offscreen on only one axis the result will
3491 // be exactly 5 planes (split-side case)
3492 // if the light origin is offscreen on two axes the result will be
3493 // exactly 4 planes (stretched corner case)
3494 for (i = 0;i < 4;i++)
3496 // quickly reject standard frustum planes that put the light
3497 // origin outside the frustum
3498 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3501 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3503 // if all the standard frustum planes were accepted, the light is onscreen
3504 // otherwise we need to generate some more planes below...
3505 if (rtlight->cached_numfrustumplanes < 4)
3507 // at least one of the stock frustum planes failed, so we need to
3508 // create one or two custom planes to enclose the light origin
3509 for (i = 0;i < 4;i++)
3511 // create a plane using the view origin and light origin, and a
3512 // single point from the frustum corner set
3513 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3514 VectorNormalize(plane.normal);
3515 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3516 // see if this plane is backwards and flip it if so
3517 for (j = 0;j < 4;j++)
3518 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3522 VectorNegate(plane.normal, plane.normal);
3524 // flipped plane, test again to see if it is now valid
3525 for (j = 0;j < 4;j++)
3526 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3528 // if the plane is still not valid, then it is dividing the
3529 // frustum and has to be rejected
3533 // we have created a valid plane, compute extra info
3534 PlaneClassify(&plane);
3536 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3538 // if we've found 5 frustum planes then we have constructed a
3539 // proper split-side case and do not need to keep searching for
3540 // planes to enclose the light origin
3541 if (rtlight->cached_numfrustumplanes == 5)
3549 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3551 plane = rtlight->cached_frustumplanes[i];
3552 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));
3557 // now add the light-space box planes if the light box is rotated, as any
3558 // caster outside the oriented light box is irrelevant (even if it passed
3559 // the worldspace light box, which is axial)
3560 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3562 for (i = 0;i < 6;i++)
3566 v[i >> 1] = (i & 1) ? -1 : 1;
3567 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3568 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3569 plane.dist = VectorNormalizeLength(plane.normal);
3570 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3571 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3577 // add the world-space reduced box planes
3578 for (i = 0;i < 6;i++)
3580 VectorClear(plane.normal);
3581 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3582 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3583 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3592 // reduce all plane distances to tightly fit the rtlight cull box, which
3594 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3595 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3596 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3597 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3598 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3599 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3600 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3601 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3602 oldnum = rtlight->cached_numfrustumplanes;
3603 rtlight->cached_numfrustumplanes = 0;
3604 for (j = 0;j < oldnum;j++)
3606 // find the nearest point on the box to this plane
3607 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3608 for (i = 1;i < 8;i++)
3610 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3611 if (bestdist > dist)
3614 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);
3615 // if the nearest point is near or behind the plane, we want this
3616 // plane, otherwise the plane is useless as it won't cull anything
3617 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3619 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3620 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3627 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3631 RSurf_ActiveWorldEntity();
3633 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3636 GL_CullFace(GL_NONE);
3637 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3638 for (;mesh;mesh = mesh->next)
3640 if (!mesh->sidetotals[r_shadow_shadowmapside])
3642 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3643 if (mesh->vertex3fbuffer)
3644 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3646 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3647 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);
3651 else if (r_refdef.scene.worldentity->model)
3652 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);
3654 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3657 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3659 qboolean zpass = false;
3662 int surfacelistindex;
3663 msurface_t *surface;
3665 // if triangle neighbors are disabled, shadowvolumes are disabled
3666 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
3669 RSurf_ActiveWorldEntity();
3671 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3674 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3676 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3677 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3679 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3680 for (;mesh;mesh = mesh->next)
3682 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3683 if (mesh->vertex3fbuffer)
3684 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3686 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3687 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3689 // increment stencil if frontface is infront of depthbuffer
3690 GL_CullFace(r_refdef.view.cullface_back);
3691 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3692 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);
3693 // decrement stencil if backface is infront of depthbuffer
3694 GL_CullFace(r_refdef.view.cullface_front);
3695 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3697 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3699 // decrement stencil if backface is behind depthbuffer
3700 GL_CullFace(r_refdef.view.cullface_front);
3701 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3702 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);
3703 // increment stencil if frontface is behind depthbuffer
3704 GL_CullFace(r_refdef.view.cullface_back);
3705 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3707 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);
3711 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3713 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3714 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3715 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3717 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3718 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3719 if (CHECKPVSBIT(trispvs, t))
3720 shadowmarklist[numshadowmark++] = t;
3722 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);
3724 else if (numsurfaces)
3726 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);
3729 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3732 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3734 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3735 vec_t relativeshadowradius;
3736 RSurf_ActiveModelEntity(ent, false, false, false);
3737 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3738 // we need to re-init the shader for each entity because the matrix changed
3739 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3740 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3741 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3742 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3743 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3744 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3745 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3746 switch (r_shadow_rendermode)
3748 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3749 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3752 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3755 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3758 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3760 // set up properties for rendering light onto this entity
3761 RSurf_ActiveModelEntity(ent, true, true, false);
3762 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3763 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3764 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3765 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3768 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3770 if (!r_refdef.scene.worldmodel->DrawLight)
3773 // set up properties for rendering light onto this entity
3774 RSurf_ActiveWorldEntity();
3775 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3776 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3777 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3778 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3780 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3782 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3785 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3787 dp_model_t *model = ent->model;
3788 if (!model->DrawLight)
3791 R_Shadow_SetupEntityLight(ent);
3793 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3795 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3798 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3802 int numleafs, numsurfaces;
3803 int *leaflist, *surfacelist;
3804 unsigned char *leafpvs;
3805 unsigned char *shadowtrispvs;
3806 unsigned char *lighttrispvs;
3807 //unsigned char *surfacesides;
3808 int numlightentities;
3809 int numlightentities_noselfshadow;
3810 int numshadowentities;
3811 int numshadowentities_noselfshadow;
3812 static entity_render_t *lightentities[MAX_EDICTS];
3813 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3814 static entity_render_t *shadowentities[MAX_EDICTS];
3815 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3818 rtlight->draw = false;
3820 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3821 // skip lights that are basically invisible (color 0 0 0)
3822 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3824 // loading is done before visibility checks because loading should happen
3825 // all at once at the start of a level, not when it stalls gameplay.
3826 // (especially important to benchmarks)
3828 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3830 if (rtlight->compiled)
3831 R_RTLight_Uncompile(rtlight);
3832 R_RTLight_Compile(rtlight);
3836 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3838 // look up the light style value at this time
3839 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3840 VectorScale(rtlight->color, f, rtlight->currentcolor);
3842 if (rtlight->selected)
3844 f = 2 + sin(realtime * M_PI * 4.0);
3845 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3849 // if lightstyle is currently off, don't draw the light
3850 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3853 // skip processing on corona-only lights
3857 // if the light box is offscreen, skip it
3858 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3861 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3862 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3864 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3866 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3868 // compiled light, world available and can receive realtime lighting
3869 // retrieve leaf information
3870 numleafs = rtlight->static_numleafs;
3871 leaflist = rtlight->static_leaflist;
3872 leafpvs = rtlight->static_leafpvs;
3873 numsurfaces = rtlight->static_numsurfaces;
3874 surfacelist = rtlight->static_surfacelist;
3875 //surfacesides = NULL;
3876 shadowtrispvs = rtlight->static_shadowtrispvs;
3877 lighttrispvs = rtlight->static_lighttrispvs;
3879 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3881 // dynamic light, world available and can receive realtime lighting
3882 // calculate lit surfaces and leafs
3883 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);
3884 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3885 leaflist = r_shadow_buffer_leaflist;
3886 leafpvs = r_shadow_buffer_leafpvs;
3887 surfacelist = r_shadow_buffer_surfacelist;
3888 //surfacesides = r_shadow_buffer_surfacesides;
3889 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3890 lighttrispvs = r_shadow_buffer_lighttrispvs;
3891 // if the reduced leaf bounds are offscreen, skip it
3892 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3903 //surfacesides = NULL;
3904 shadowtrispvs = NULL;
3905 lighttrispvs = NULL;
3907 // check if light is illuminating any visible leafs
3910 for (i = 0;i < numleafs;i++)
3911 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3917 // make a list of lit entities and shadow casting entities
3918 numlightentities = 0;
3919 numlightentities_noselfshadow = 0;
3920 numshadowentities = 0;
3921 numshadowentities_noselfshadow = 0;
3923 // add dynamic entities that are lit by the light
3924 for (i = 0;i < r_refdef.scene.numentities;i++)
3927 entity_render_t *ent = r_refdef.scene.entities[i];
3929 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3931 // skip the object entirely if it is not within the valid
3932 // shadow-casting region (which includes the lit region)
3933 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3935 if (!(model = ent->model))
3937 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3939 // this entity wants to receive light, is visible, and is
3940 // inside the light box
3941 // TODO: check if the surfaces in the model can receive light
3942 // so now check if it's in a leaf seen by the light
3943 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))
3945 if (ent->flags & RENDER_NOSELFSHADOW)
3946 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3948 lightentities[numlightentities++] = ent;
3949 // since it is lit, it probably also casts a shadow...
3950 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3951 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3952 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3954 // note: exterior models without the RENDER_NOSELFSHADOW
3955 // flag still create a RENDER_NOSELFSHADOW shadow but
3956 // are lit normally, this means that they are
3957 // self-shadowing but do not shadow other
3958 // RENDER_NOSELFSHADOW entities such as the gun
3959 // (very weird, but keeps the player shadow off the gun)
3960 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3961 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3963 shadowentities[numshadowentities++] = ent;
3966 else if (ent->flags & RENDER_SHADOW)
3968 // this entity is not receiving light, but may still need to
3970 // TODO: check if the surfaces in the model can cast shadow
3971 // now check if it is in a leaf seen by the light
3972 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))
3974 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3975 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3976 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3978 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3979 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3981 shadowentities[numshadowentities++] = ent;
3986 // return if there's nothing at all to light
3987 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3990 // count this light in the r_speeds
3991 r_refdef.stats.lights++;
3993 // flag it as worth drawing later
3994 rtlight->draw = true;
3996 // cache all the animated entities that cast a shadow but are not visible
3997 for (i = 0;i < numshadowentities;i++)
3998 if (!shadowentities[i]->animcache_vertex3f)
3999 R_AnimCache_GetEntity(shadowentities[i], false, false);
4000 for (i = 0;i < numshadowentities_noselfshadow;i++)
4001 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
4002 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4004 // allocate some temporary memory for rendering this light later in the frame
4005 // reusable buffers need to be copied, static data can be used as-is
4006 rtlight->cached_numlightentities = numlightentities;
4007 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
4008 rtlight->cached_numshadowentities = numshadowentities;
4009 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4010 rtlight->cached_numsurfaces = numsurfaces;
4011 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4012 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4013 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4014 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4015 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4017 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4018 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4019 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4020 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4021 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4025 // compiled light data
4026 rtlight->cached_shadowtrispvs = shadowtrispvs;
4027 rtlight->cached_lighttrispvs = lighttrispvs;
4028 rtlight->cached_surfacelist = surfacelist;
4032 void R_Shadow_DrawLight(rtlight_t *rtlight)
4036 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4037 int numlightentities;
4038 int numlightentities_noselfshadow;
4039 int numshadowentities;
4040 int numshadowentities_noselfshadow;
4041 entity_render_t **lightentities;
4042 entity_render_t **lightentities_noselfshadow;
4043 entity_render_t **shadowentities;
4044 entity_render_t **shadowentities_noselfshadow;
4046 static unsigned char entitysides[MAX_EDICTS];
4047 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4048 vec3_t nearestpoint;
4050 qboolean castshadows;
4053 // check if we cached this light this frame (meaning it is worth drawing)
4057 numlightentities = rtlight->cached_numlightentities;
4058 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4059 numshadowentities = rtlight->cached_numshadowentities;
4060 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4061 numsurfaces = rtlight->cached_numsurfaces;
4062 lightentities = rtlight->cached_lightentities;
4063 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4064 shadowentities = rtlight->cached_shadowentities;
4065 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4066 shadowtrispvs = rtlight->cached_shadowtrispvs;
4067 lighttrispvs = rtlight->cached_lighttrispvs;
4068 surfacelist = rtlight->cached_surfacelist;
4070 // set up a scissor rectangle for this light
4071 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4074 // don't let sound skip if going slow
4075 if (r_refdef.scene.extraupdate)
4078 // make this the active rtlight for rendering purposes
4079 R_Shadow_RenderMode_ActiveLight(rtlight);
4081 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4083 // optionally draw visible shape of the shadow volumes
4084 // for performance analysis by level designers
4085 R_Shadow_RenderMode_VisibleShadowVolumes();
4087 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4088 for (i = 0;i < numshadowentities;i++)
4089 R_Shadow_DrawEntityShadow(shadowentities[i]);
4090 for (i = 0;i < numshadowentities_noselfshadow;i++)
4091 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4092 R_Shadow_RenderMode_VisibleLighting(false, false);
4095 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4097 // optionally draw the illuminated areas
4098 // for performance analysis by level designers
4099 R_Shadow_RenderMode_VisibleLighting(false, false);
4101 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4102 for (i = 0;i < numlightentities;i++)
4103 R_Shadow_DrawEntityLight(lightentities[i]);
4104 for (i = 0;i < numlightentities_noselfshadow;i++)
4105 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4108 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4110 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4111 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4112 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4113 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4115 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
4116 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4117 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4119 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4125 int receivermask = 0;
4126 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4127 Matrix4x4_Abs(&radiustolight);
4129 r_shadow_shadowmaplod = 0;
4130 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4131 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
4132 r_shadow_shadowmaplod = i;
4134 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4136 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4138 surfacesides = NULL;
4141 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4143 castermask = rtlight->static_shadowmap_casters;
4144 receivermask = rtlight->static_shadowmap_receivers;
4148 surfacesides = r_shadow_buffer_surfacesides;
4149 for(i = 0;i < numsurfaces;i++)
4151 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4152 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4153 castermask |= surfacesides[i];
4154 receivermask |= surfacesides[i];
4158 if (receivermask < 0x3F)
4160 for (i = 0;i < numlightentities;i++)
4161 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4162 if (receivermask < 0x3F)
4163 for(i = 0; i < numlightentities_noselfshadow;i++)
4164 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4167 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4171 for (i = 0;i < numshadowentities;i++)
4172 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4173 for (i = 0;i < numshadowentities_noselfshadow;i++)
4174 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4177 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4179 // render shadow casters into 6 sided depth texture
4180 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4182 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
4183 if (! (castermask & (1 << side))) continue;
4185 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4186 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4187 R_Shadow_DrawEntityShadow(shadowentities[i]);
4190 if (numlightentities_noselfshadow)
4192 // render lighting using the depth texture as shadowmap
4193 // draw lighting in the unmasked areas
4194 R_Shadow_RenderMode_Lighting(false, false, true);
4195 for (i = 0;i < numlightentities_noselfshadow;i++)
4196 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4199 // render shadow casters into 6 sided depth texture
4200 if (numshadowentities_noselfshadow)
4202 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4204 R_Shadow_RenderMode_ShadowMap(side, 0, size);
4205 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
4206 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4210 // render lighting using the depth texture as shadowmap
4211 // draw lighting in the unmasked areas
4212 R_Shadow_RenderMode_Lighting(false, false, true);
4213 // draw lighting in the unmasked areas
4215 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4216 for (i = 0;i < numlightentities;i++)
4217 R_Shadow_DrawEntityLight(lightentities[i]);
4219 else if (castshadows && vid.stencil)
4221 // draw stencil shadow volumes to mask off pixels that are in shadow
4222 // so that they won't receive lighting
4223 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4224 R_Shadow_ClearStencil();
4227 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4228 for (i = 0;i < numshadowentities;i++)
4229 R_Shadow_DrawEntityShadow(shadowentities[i]);
4231 // draw lighting in the unmasked areas
4232 R_Shadow_RenderMode_Lighting(true, false, false);
4233 for (i = 0;i < numlightentities_noselfshadow;i++)
4234 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4236 for (i = 0;i < numshadowentities_noselfshadow;i++)
4237 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4239 // draw lighting in the unmasked areas
4240 R_Shadow_RenderMode_Lighting(true, false, false);
4242 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4243 for (i = 0;i < numlightentities;i++)
4244 R_Shadow_DrawEntityLight(lightentities[i]);
4248 // draw lighting in the unmasked areas
4249 R_Shadow_RenderMode_Lighting(false, false, false);
4251 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4252 for (i = 0;i < numlightentities;i++)
4253 R_Shadow_DrawEntityLight(lightentities[i]);
4254 for (i = 0;i < numlightentities_noselfshadow;i++)
4255 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4258 if (r_shadow_usingdeferredprepass)
4260 // when rendering deferred lighting, we simply rasterize the box
4261 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4262 R_Shadow_RenderMode_DrawDeferredLight(false, true);
4263 else if (castshadows && vid.stencil)
4264 R_Shadow_RenderMode_DrawDeferredLight(true, false);
4266 R_Shadow_RenderMode_DrawDeferredLight(false, false);
4269 if (r_shadow_particletrace.integer)
4270 R_Shadow_RenderParticlesForLight(rtlight);
4273 static void R_Shadow_FreeDeferred(void)
4275 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
4276 r_shadow_prepassgeometryfbo = 0;
4278 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
4279 r_shadow_prepasslightingdiffusespecularfbo = 0;
4281 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
4282 r_shadow_prepasslightingdiffusefbo = 0;
4284 if (r_shadow_prepassgeometrydepthtexture)
4285 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
4286 r_shadow_prepassgeometrydepthtexture = NULL;
4288 if (r_shadow_prepassgeometrydepthcolortexture)
4289 R_FreeTexture(r_shadow_prepassgeometrydepthcolortexture);
4290 r_shadow_prepassgeometrydepthcolortexture = NULL;
4292 if (r_shadow_prepassgeometrynormalmaptexture)
4293 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4294 r_shadow_prepassgeometrynormalmaptexture = NULL;
4296 if (r_shadow_prepasslightingdiffusetexture)
4297 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
4298 r_shadow_prepasslightingdiffusetexture = NULL;
4300 if (r_shadow_prepasslightingspeculartexture)
4301 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4302 r_shadow_prepasslightingspeculartexture = NULL;
4305 void R_Shadow_DrawPrepass(void)
4313 entity_render_t *ent;
4314 float clearcolor[4];
4316 R_Mesh_ResetTextureState();
4318 GL_ColorMask(1,1,1,1);
4319 GL_BlendFunc(GL_ONE, GL_ZERO);
4322 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4323 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4324 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4325 if (r_timereport_active)
4326 R_TimeReport("prepasscleargeom");
4328 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4329 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4330 if (r_timereport_active)
4331 R_TimeReport("prepassworld");
4333 for (i = 0;i < r_refdef.scene.numentities;i++)
4335 if (!r_refdef.viewcache.entityvisible[i])
4337 ent = r_refdef.scene.entities[i];
4338 if (ent->model && ent->model->DrawPrepass != NULL)
4339 ent->model->DrawPrepass(ent);
4342 if (r_timereport_active)
4343 R_TimeReport("prepassmodels");
4345 GL_DepthMask(false);
4346 GL_ColorMask(1,1,1,1);
4349 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4350 Vector4Set(clearcolor, 0, 0, 0, 0);
4351 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4352 if (r_timereport_active)
4353 R_TimeReport("prepassclearlit");
4355 R_Shadow_RenderMode_Begin();
4357 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4358 if (r_shadow_debuglight.integer >= 0)
4360 lightindex = r_shadow_debuglight.integer;
4361 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4362 if (light && (light->flags & flag) && light->rtlight.draw)
4363 R_Shadow_DrawLight(&light->rtlight);
4367 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4368 for (lightindex = 0;lightindex < range;lightindex++)
4370 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4371 if (light && (light->flags & flag) && light->rtlight.draw)
4372 R_Shadow_DrawLight(&light->rtlight);
4375 if (r_refdef.scene.rtdlight)
4376 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4377 if (r_refdef.scene.lights[lnum]->draw)
4378 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4380 R_Mesh_ResetRenderTargets();
4382 R_Shadow_RenderMode_End();
4384 if (r_timereport_active)
4385 R_TimeReport("prepasslights");
4388 void R_Shadow_DrawLightSprites(void);
4389 void R_Shadow_PrepareLights(void)
4399 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4400 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4401 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
4402 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4403 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4404 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4405 R_Shadow_FreeShadowMaps();
4407 r_shadow_usingshadowmaportho = false;
4409 switch (vid.renderpath)
4411 case RENDERPATH_GL20:
4412 case RENDERPATH_D3D9:
4413 case RENDERPATH_D3D10:
4414 case RENDERPATH_D3D11:
4415 case RENDERPATH_SOFT:
4416 case RENDERPATH_GLES2:
4417 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4419 r_shadow_usingdeferredprepass = false;
4420 if (r_shadow_prepass_width)
4421 R_Shadow_FreeDeferred();
4422 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4426 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4428 R_Shadow_FreeDeferred();
4430 r_shadow_usingdeferredprepass = true;
4431 r_shadow_prepass_width = vid.width;
4432 r_shadow_prepass_height = vid.height;
4433 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4434 switch (vid.renderpath)
4436 case RENDERPATH_D3D9:
4437 r_shadow_prepassgeometrydepthcolortexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrydepthcolormap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4442 r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4443 r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4444 r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4446 // set up the geometry pass fbo (depth + normalmap)
4447 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4448 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4449 // render depth into one texture and normalmap into the other
4450 if (qglDrawBuffersARB)
4452 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4453 qglReadBuffer(GL_NONE);CHECKGLERROR
4454 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4455 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4457 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4458 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4459 r_shadow_usingdeferredprepass = false;
4463 // set up the lighting pass fbo (diffuse + specular)
4464 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4465 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4466 // render diffuse into one texture and specular into another,
4467 // with depth and normalmap bound as textures,
4468 // with depth bound as attachment as well
4469 if (qglDrawBuffersARB)
4471 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4472 qglReadBuffer(GL_NONE);CHECKGLERROR
4473 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4474 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4476 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4477 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4478 r_shadow_usingdeferredprepass = false;
4482 // set up the lighting pass fbo (diffuse)
4483 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4484 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4485 // render diffuse into one texture,
4486 // with depth and normalmap bound as textures,
4487 // with depth bound as attachment as well
4488 if (qglDrawBuffersARB)
4490 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4491 qglReadBuffer(GL_NONE);CHECKGLERROR
4492 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4493 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4495 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4496 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4497 r_shadow_usingdeferredprepass = false;
4502 case RENDERPATH_GL13:
4503 case RENDERPATH_GL11:
4504 r_shadow_usingdeferredprepass = false;
4508 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);
4510 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4511 if (r_shadow_debuglight.integer >= 0)
4513 lightindex = r_shadow_debuglight.integer;
4514 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4515 if (light && (light->flags & flag))
4516 R_Shadow_PrepareLight(&light->rtlight);
4520 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4521 for (lightindex = 0;lightindex < range;lightindex++)
4523 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4524 if (light && (light->flags & flag))
4525 R_Shadow_PrepareLight(&light->rtlight);
4528 if (r_refdef.scene.rtdlight)
4530 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4531 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4533 else if(gl_flashblend.integer)
4535 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4537 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4538 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4539 VectorScale(rtlight->color, f, rtlight->currentcolor);
4543 if (r_editlights.integer)
4544 R_Shadow_DrawLightSprites();
4546 R_Shadow_UpdateBounceGridTexture();
4549 void R_Shadow_DrawLights(void)
4557 R_Shadow_RenderMode_Begin();
4559 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4560 if (r_shadow_debuglight.integer >= 0)
4562 lightindex = r_shadow_debuglight.integer;
4563 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4564 if (light && (light->flags & flag))
4565 R_Shadow_DrawLight(&light->rtlight);
4569 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4570 for (lightindex = 0;lightindex < range;lightindex++)
4572 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4573 if (light && (light->flags & flag))
4574 R_Shadow_DrawLight(&light->rtlight);
4577 if (r_refdef.scene.rtdlight)
4578 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4579 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4581 R_Shadow_RenderMode_End();
4584 extern const float r_screenvertex3f[12];
4585 extern void R_SetupView(qboolean allowwaterclippingplane);
4586 extern void R_ResetViewRendering3D(void);
4587 extern void R_ResetViewRendering2D(void);
4588 extern cvar_t r_shadows;
4589 extern cvar_t r_shadows_darken;
4590 extern cvar_t r_shadows_drawafterrtlighting;
4591 extern cvar_t r_shadows_castfrombmodels;
4592 extern cvar_t r_shadows_throwdistance;
4593 extern cvar_t r_shadows_throwdirection;
4594 extern cvar_t r_shadows_focus;
4595 extern cvar_t r_shadows_shadowmapscale;
4597 void R_Shadow_PrepareModelShadows(void)
4600 float scale, size, radius, dot1, dot2;
4601 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4602 entity_render_t *ent;
4604 if (!r_refdef.scene.numentities)
4607 switch (r_shadow_shadowmode)
4609 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4610 if (r_shadows.integer >= 2)
4613 case R_SHADOW_SHADOWMODE_STENCIL:
4614 for (i = 0;i < r_refdef.scene.numentities;i++)
4616 ent = r_refdef.scene.entities[i];
4617 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4618 R_AnimCache_GetEntity(ent, false, false);
4625 size = 2*r_shadow_shadowmapmaxsize;
4626 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4627 radius = 0.5f * size / scale;
4629 Math_atov(r_shadows_throwdirection.string, shadowdir);
4630 VectorNormalize(shadowdir);
4631 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4632 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4633 if (fabs(dot1) <= fabs(dot2))
4634 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4636 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4637 VectorNormalize(shadowforward);
4638 CrossProduct(shadowdir, shadowforward, shadowright);
4639 Math_atov(r_shadows_focus.string, shadowfocus);
4640 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4641 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4642 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4643 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4644 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4646 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4648 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4649 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4650 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4651 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4652 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4653 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4655 for (i = 0;i < r_refdef.scene.numentities;i++)
4657 ent = r_refdef.scene.entities[i];
4658 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4660 // cast shadows from anything of the map (submodels are optional)
4661 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4662 R_AnimCache_GetEntity(ent, false, false);
4666 void R_DrawModelShadowMaps(void)
4669 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4670 entity_render_t *ent;
4671 vec3_t relativelightorigin;
4672 vec3_t relativelightdirection, relativeforward, relativeright;
4673 vec3_t relativeshadowmins, relativeshadowmaxs;
4674 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4676 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4677 r_viewport_t viewport;
4679 float clearcolor[4];
4681 if (!r_refdef.scene.numentities)
4684 switch (r_shadow_shadowmode)
4686 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4692 R_ResetViewRendering3D();
4693 R_Shadow_RenderMode_Begin();
4694 R_Shadow_RenderMode_ActiveLight(NULL);
4696 switch (r_shadow_shadowmode)
4698 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4699 if (!r_shadow_shadowmap2dtexture)
4700 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4701 fbo = r_shadow_fbo2d;
4702 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4703 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4704 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4710 size = 2*r_shadow_shadowmapmaxsize;
4711 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4712 radius = 0.5f / scale;
4713 nearclip = -r_shadows_throwdistance.value;
4714 farclip = r_shadows_throwdistance.value;
4715 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4717 r_shadow_shadowmap_parameters[0] = size;
4718 r_shadow_shadowmap_parameters[1] = size;
4719 r_shadow_shadowmap_parameters[2] = 1.0;
4720 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4722 Math_atov(r_shadows_throwdirection.string, shadowdir);
4723 VectorNormalize(shadowdir);
4724 Math_atov(r_shadows_focus.string, shadowfocus);
4725 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4726 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4727 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4728 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4729 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4730 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4731 if (fabs(dot1) <= fabs(dot2))
4732 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4734 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4735 VectorNormalize(shadowforward);
4736 VectorM(scale, shadowforward, &m[0]);
4737 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4739 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4740 CrossProduct(shadowdir, shadowforward, shadowright);
4741 VectorM(scale, shadowright, &m[4]);
4742 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4743 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4744 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4745 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4746 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4747 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4749 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4751 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
4752 R_SetupShader_DepthOrShadow();
4753 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4756 R_SetViewport(&viewport);
4757 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4758 Vector4Set(clearcolor, 1,1,1,1);
4759 // in D3D9 we have to render to a color texture shadowmap
4760 // in GL we render directly to a depth texture only
4761 if (r_shadow_shadowmap2dtexture)
4762 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4764 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4765 // render into a slightly restricted region so that the borders of the
4766 // shadowmap area fade away, rather than streaking across everything
4767 // outside the usable area
4768 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4772 R_Mesh_ResetRenderTargets();
4773 R_SetupShader_ShowDepth();
4774 GL_ColorMask(1,1,1,1);
4775 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4778 for (i = 0;i < r_refdef.scene.numentities;i++)
4780 ent = r_refdef.scene.entities[i];
4782 // cast shadows from anything of the map (submodels are optional)
4783 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4785 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4786 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4787 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4788 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4789 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4790 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4791 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4792 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4793 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4794 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4795 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4796 RSurf_ActiveModelEntity(ent, false, false, false);
4797 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4798 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4805 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4807 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4809 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4810 Cvar_SetValueQuick(&r_test, 0);
4815 R_Shadow_RenderMode_End();
4817 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4818 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4819 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4820 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4821 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4822 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4824 switch (vid.renderpath)
4826 case RENDERPATH_GL11:
4827 case RENDERPATH_GL13:
4828 case RENDERPATH_GL20:
4829 case RENDERPATH_SOFT:
4830 case RENDERPATH_GLES2:
4832 case RENDERPATH_D3D9:
4833 case RENDERPATH_D3D10:
4834 case RENDERPATH_D3D11:
4835 #ifdef OPENGL_ORIENTATION
4836 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4837 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
4838 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
4839 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
4841 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4842 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
4843 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
4844 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
4849 r_shadow_usingshadowmaportho = true;
4850 switch (r_shadow_shadowmode)
4852 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4853 r_shadow_usingshadowmap2d = true;
4860 void R_DrawModelShadows(void)
4863 float relativethrowdistance;
4864 entity_render_t *ent;
4865 vec3_t relativelightorigin;
4866 vec3_t relativelightdirection;
4867 vec3_t relativeshadowmins, relativeshadowmaxs;
4868 vec3_t tmp, shadowdir;
4870 if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4873 R_ResetViewRendering3D();
4874 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4875 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4876 R_Shadow_RenderMode_Begin();
4877 R_Shadow_RenderMode_ActiveLight(NULL);
4878 r_shadow_lightscissor[0] = r_refdef.view.x;
4879 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4880 r_shadow_lightscissor[2] = r_refdef.view.width;
4881 r_shadow_lightscissor[3] = r_refdef.view.height;
4882 R_Shadow_RenderMode_StencilShadowVolumes(false);
4885 if (r_shadows.integer == 2)
4887 Math_atov(r_shadows_throwdirection.string, shadowdir);
4888 VectorNormalize(shadowdir);
4891 R_Shadow_ClearStencil();
4893 for (i = 0;i < r_refdef.scene.numentities;i++)
4895 ent = r_refdef.scene.entities[i];
4897 // cast shadows from anything of the map (submodels are optional)
4898 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4900 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4901 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4902 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4903 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4904 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4907 if(ent->entitynumber != 0)
4909 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4911 // FIXME handle this
4912 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4916 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4917 int entnum, entnum2, recursion;
4918 entnum = entnum2 = ent->entitynumber;
4919 for(recursion = 32; recursion > 0; --recursion)
4921 entnum2 = cl.entities[entnum].state_current.tagentity;
4922 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4927 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4929 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4930 // transform into modelspace of OUR entity
4931 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4932 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4935 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4939 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4942 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4943 RSurf_ActiveModelEntity(ent, false, false, false);
4944 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4945 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4949 // not really the right mode, but this will disable any silly stencil features
4950 R_Shadow_RenderMode_End();
4952 // set up ortho view for rendering this pass
4953 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4954 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4955 //GL_ScissorTest(true);
4956 //R_EntityMatrix(&identitymatrix);
4957 //R_Mesh_ResetTextureState();
4958 R_ResetViewRendering2D();
4960 // set up a darkening blend on shadowed areas
4961 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4962 //GL_DepthRange(0, 1);
4963 //GL_DepthTest(false);
4964 //GL_DepthMask(false);
4965 //GL_PolygonOffset(0, 0);CHECKGLERROR
4966 GL_Color(0, 0, 0, r_shadows_darken.value);
4967 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4968 //GL_DepthFunc(GL_ALWAYS);
4969 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
4971 // apply the blend to the shadowed areas
4972 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
4973 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4974 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4976 // restore the viewport
4977 R_SetViewport(&r_refdef.view.viewport);
4979 // restore other state to normal
4980 //R_Shadow_RenderMode_End();
4983 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4986 vec3_t centerorigin;
4988 // if it's too close, skip it
4989 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4991 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4994 if (usequery && r_numqueries + 2 <= r_maxqueries)
4996 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4997 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4998 // 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
4999 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5001 switch(vid.renderpath)
5003 case RENDERPATH_GL20:
5004 case RENDERPATH_GL13:
5005 case RENDERPATH_GL11:
5006 case RENDERPATH_GLES2:
5008 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5009 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5010 GL_DepthFunc(GL_ALWAYS);
5011 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5012 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
5013 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5014 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5015 GL_DepthFunc(GL_LEQUAL);
5016 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5017 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5018 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
5019 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5020 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5023 case RENDERPATH_D3D9:
5024 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5026 case RENDERPATH_D3D10:
5027 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5029 case RENDERPATH_D3D11:
5030 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5032 case RENDERPATH_SOFT:
5033 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5037 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5040 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5042 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5045 GLint allpixels = 0, visiblepixels = 0;
5046 // now we have to check the query result
5047 if (rtlight->corona_queryindex_visiblepixels)
5049 switch(vid.renderpath)
5051 case RENDERPATH_GL20:
5052 case RENDERPATH_GL13:
5053 case RENDERPATH_GL11:
5054 case RENDERPATH_GLES2:
5056 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5057 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5060 case RENDERPATH_D3D9:
5061 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5063 case RENDERPATH_D3D10:
5064 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5066 case RENDERPATH_D3D11:
5067 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5069 case RENDERPATH_SOFT:
5070 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5073 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
5074 if (visiblepixels < 1 || allpixels < 1)
5076 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5077 cscale *= rtlight->corona_visibility;
5081 // FIXME: these traces should scan all render entities instead of cl.world
5082 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
5085 VectorScale(rtlight->currentcolor, cscale, color);
5086 if (VectorLength(color) > (1.0f / 256.0f))
5089 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
5092 VectorNegate(color, color);
5093 switch(vid.renderpath)
5095 case RENDERPATH_GL11:
5096 case RENDERPATH_GL13:
5097 case RENDERPATH_GL20:
5098 case RENDERPATH_GLES2:
5099 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
5101 case RENDERPATH_D3D9:
5103 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
5106 case RENDERPATH_D3D10:
5107 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5109 case RENDERPATH_D3D11:
5110 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5112 case RENDERPATH_SOFT:
5113 DPSOFTRAST_BlendSubtract(true);
5117 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5118 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);
5119 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5122 switch(vid.renderpath)
5124 case RENDERPATH_GL11:
5125 case RENDERPATH_GL13:
5126 case RENDERPATH_GL20:
5127 case RENDERPATH_GLES2:
5128 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
5130 case RENDERPATH_D3D9:
5132 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
5135 case RENDERPATH_D3D10:
5136 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5138 case RENDERPATH_D3D11:
5139 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5141 case RENDERPATH_SOFT:
5142 DPSOFTRAST_BlendSubtract(false);
5149 void R_Shadow_DrawCoronas(void)
5152 qboolean usequery = false;
5157 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
5159 if (r_waterstate.renderingscene)
5161 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5162 R_EntityMatrix(&identitymatrix);
5164 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5166 // check occlusion of coronas
5167 // use GL_ARB_occlusion_query if available
5168 // otherwise use raytraces
5170 switch (vid.renderpath)
5172 case RENDERPATH_GL11:
5173 case RENDERPATH_GL13:
5174 case RENDERPATH_GL20:
5175 case RENDERPATH_GLES2:
5176 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
5179 GL_ColorMask(0,0,0,0);
5180 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
5181 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
5184 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
5185 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
5187 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
5190 RSurf_ActiveWorldEntity();
5191 GL_BlendFunc(GL_ONE, GL_ZERO);
5192 GL_CullFace(GL_NONE);
5193 GL_DepthMask(false);
5194 GL_DepthRange(0, 1);
5195 GL_PolygonOffset(0, 0);
5197 R_Mesh_ResetTextureState();
5198 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
5201 case RENDERPATH_D3D9:
5203 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5205 case RENDERPATH_D3D10:
5206 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5208 case RENDERPATH_D3D11:
5209 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5211 case RENDERPATH_SOFT:
5213 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5216 for (lightindex = 0;lightindex < range;lightindex++)
5218 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5221 rtlight = &light->rtlight;
5222 rtlight->corona_visibility = 0;
5223 rtlight->corona_queryindex_visiblepixels = 0;
5224 rtlight->corona_queryindex_allpixels = 0;
5225 if (!(rtlight->flags & flag))
5227 if (rtlight->corona <= 0)
5229 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
5231 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5233 for (i = 0;i < r_refdef.scene.numlights;i++)
5235 rtlight = r_refdef.scene.lights[i];
5236 rtlight->corona_visibility = 0;
5237 rtlight->corona_queryindex_visiblepixels = 0;
5238 rtlight->corona_queryindex_allpixels = 0;
5239 if (!(rtlight->flags & flag))
5241 if (rtlight->corona <= 0)
5243 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5246 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5248 // now draw the coronas using the query data for intensity info
5249 for (lightindex = 0;lightindex < range;lightindex++)
5251 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5254 rtlight = &light->rtlight;
5255 if (rtlight->corona_visibility <= 0)
5257 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5259 for (i = 0;i < r_refdef.scene.numlights;i++)
5261 rtlight = r_refdef.scene.lights[i];
5262 if (rtlight->corona_visibility <= 0)
5264 if (gl_flashblend.integer)
5265 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
5267 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5273 dlight_t *R_Shadow_NewWorldLight(void)
5275 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
5278 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)
5281 // validate parameters
5282 if (style < 0 || style >= MAX_LIGHTSTYLES)
5284 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
5290 // copy to light properties
5291 VectorCopy(origin, light->origin);
5292 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
5293 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
5294 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
5296 light->color[0] = max(color[0], 0);
5297 light->color[1] = max(color[1], 0);
5298 light->color[2] = max(color[2], 0);
5300 light->color[0] = color[0];
5301 light->color[1] = color[1];
5302 light->color[2] = color[2];
5303 light->radius = max(radius, 0);
5304 light->style = style;
5305 light->shadow = shadowenable;
5306 light->corona = corona;
5307 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
5308 light->coronasizescale = coronasizescale;
5309 light->ambientscale = ambientscale;
5310 light->diffusescale = diffusescale;
5311 light->specularscale = specularscale;
5312 light->flags = flags;
5314 // update renderable light data
5315 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
5316 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);
5319 void R_Shadow_FreeWorldLight(dlight_t *light)
5321 if (r_shadow_selectedlight == light)
5322 r_shadow_selectedlight = NULL;
5323 R_RTLight_Uncompile(&light->rtlight);
5324 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
5327 void R_Shadow_ClearWorldLights(void)
5331 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5332 for (lightindex = 0;lightindex < range;lightindex++)
5334 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5336 R_Shadow_FreeWorldLight(light);
5338 r_shadow_selectedlight = NULL;
5341 void R_Shadow_SelectLight(dlight_t *light)
5343 if (r_shadow_selectedlight)
5344 r_shadow_selectedlight->selected = false;
5345 r_shadow_selectedlight = light;
5346 if (r_shadow_selectedlight)
5347 r_shadow_selectedlight->selected = true;
5350 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5352 // this is never batched (there can be only one)
5354 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
5355 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5356 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5359 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5364 skinframe_t *skinframe;
5367 // this is never batched (due to the ent parameter changing every time)
5368 // so numsurfaces == 1 and surfacelist[0] == lightnumber
5369 const dlight_t *light = (dlight_t *)ent;
5372 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
5375 VectorScale(light->color, intensity, spritecolor);
5376 if (VectorLength(spritecolor) < 0.1732f)
5377 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
5378 if (VectorLength(spritecolor) > 1.0f)
5379 VectorNormalize(spritecolor);
5381 // draw light sprite
5382 if (light->cubemapname[0] && !light->shadow)
5383 skinframe = r_editlights_sprcubemapnoshadowlight;
5384 else if (light->cubemapname[0])
5385 skinframe = r_editlights_sprcubemaplight;
5386 else if (!light->shadow)
5387 skinframe = r_editlights_sprnoshadowlight;
5389 skinframe = r_editlights_sprlight;
5391 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);
5392 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5394 // draw selection sprite if light is selected
5395 if (light->selected)
5397 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5398 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5399 // VorteX todo: add normalmode/realtime mode light overlay sprites?
5403 void R_Shadow_DrawLightSprites(void)
5407 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5408 for (lightindex = 0;lightindex < range;lightindex++)
5410 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5412 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
5414 if (!r_editlights_lockcursor)
5415 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
5418 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
5423 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
5424 if (lightindex >= range)
5426 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5429 rtlight = &light->rtlight;
5430 //if (!(rtlight->flags & flag))
5432 VectorCopy(rtlight->shadoworigin, origin);
5433 *radius = rtlight->radius;
5434 VectorCopy(rtlight->color, color);
5438 void R_Shadow_SelectLightInView(void)
5440 float bestrating, rating, temp[3];
5444 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5448 if (r_editlights_lockcursor)
5450 for (lightindex = 0;lightindex < range;lightindex++)
5452 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5455 VectorSubtract(light->origin, r_refdef.view.origin, temp);
5456 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
5459 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
5460 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
5462 bestrating = rating;
5467 R_Shadow_SelectLight(best);
5470 void R_Shadow_LoadWorldLights(void)
5472 int n, a, style, shadow, flags;
5473 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
5474 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
5475 if (cl.worldmodel == NULL)
5477 Con_Print("No map loaded.\n");
5480 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5481 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5491 for (;COM_Parse(t, true) && strcmp(
5492 if (COM_Parse(t, true))
5494 if (com_token[0] == '!')
5497 origin[0] = atof(com_token+1);
5500 origin[0] = atof(com_token);
5505 while (*s && *s != '\n' && *s != '\r')
5511 // check for modifier flags
5518 #if _MSC_VER >= 1400
5519 #define sscanf sscanf_s
5521 cubemapname[sizeof(cubemapname)-1] = 0;
5522 #if MAX_QPATH != 128
5523 #error update this code if MAX_QPATH changes
5525 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
5526 #if _MSC_VER >= 1400
5527 , sizeof(cubemapname)
5529 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5532 flags = LIGHTFLAG_REALTIMEMODE;
5540 coronasizescale = 0.25f;
5542 VectorClear(angles);
5545 if (a < 9 || !strcmp(cubemapname, "\"\""))
5547 // remove quotes on cubemapname
5548 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5551 namelen = strlen(cubemapname) - 2;
5552 memmove(cubemapname, cubemapname + 1, namelen);
5553 cubemapname[namelen] = '\0';
5557 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);
5560 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5568 Con_Printf("invalid rtlights file \"%s\"\n", name);
5569 Mem_Free(lightsstring);
5573 void R_Shadow_SaveWorldLights(void)
5577 size_t bufchars, bufmaxchars;
5579 char name[MAX_QPATH];
5580 char line[MAX_INPUTLINE];
5581 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5582 // I hate lines which are 3 times my screen size :( --blub
5585 if (cl.worldmodel == NULL)
5587 Con_Print("No map loaded.\n");
5590 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5591 bufchars = bufmaxchars = 0;
5593 for (lightindex = 0;lightindex < range;lightindex++)
5595 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5598 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5599 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);
5600 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5601 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]);
5603 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);
5604 if (bufchars + strlen(line) > bufmaxchars)
5606 bufmaxchars = bufchars + strlen(line) + 2048;
5608 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5612 memcpy(buf, oldbuf, bufchars);
5618 memcpy(buf + bufchars, line, strlen(line));
5619 bufchars += strlen(line);
5623 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5628 void R_Shadow_LoadLightsFile(void)
5631 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5632 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5633 if (cl.worldmodel == NULL)
5635 Con_Print("No map loaded.\n");
5638 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5639 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5647 while (*s && *s != '\n' && *s != '\r')
5653 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);
5657 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);
5660 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5661 radius = bound(15, radius, 4096);
5662 VectorScale(color, (2.0f / (8388608.0f)), color);
5663 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5671 Con_Printf("invalid lights file \"%s\"\n", name);
5672 Mem_Free(lightsstring);
5676 // tyrlite/hmap2 light types in the delay field
5677 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5679 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5691 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5692 char key[256], value[MAX_INPUTLINE];
5694 if (cl.worldmodel == NULL)
5696 Con_Print("No map loaded.\n");
5699 // try to load a .ent file first
5700 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5701 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5702 // and if that is not found, fall back to the bsp file entity string
5704 data = cl.worldmodel->brush.entities;
5707 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5709 type = LIGHTTYPE_MINUSX;
5710 origin[0] = origin[1] = origin[2] = 0;
5711 originhack[0] = originhack[1] = originhack[2] = 0;
5712 angles[0] = angles[1] = angles[2] = 0;
5713 color[0] = color[1] = color[2] = 1;
5714 light[0] = light[1] = light[2] = 1;light[3] = 300;
5715 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5725 if (!COM_ParseToken_Simple(&data, false, false))
5727 if (com_token[0] == '}')
5728 break; // end of entity
5729 if (com_token[0] == '_')
5730 strlcpy(key, com_token + 1, sizeof(key));
5732 strlcpy(key, com_token, sizeof(key));
5733 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5734 key[strlen(key)-1] = 0;
5735 if (!COM_ParseToken_Simple(&data, false, false))
5737 strlcpy(value, com_token, sizeof(value));
5739 // now that we have the key pair worked out...
5740 if (!strcmp("light", key))
5742 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5746 light[0] = vec[0] * (1.0f / 256.0f);
5747 light[1] = vec[0] * (1.0f / 256.0f);
5748 light[2] = vec[0] * (1.0f / 256.0f);
5754 light[0] = vec[0] * (1.0f / 255.0f);
5755 light[1] = vec[1] * (1.0f / 255.0f);
5756 light[2] = vec[2] * (1.0f / 255.0f);
5760 else if (!strcmp("delay", key))
5762 else if (!strcmp("origin", key))
5763 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5764 else if (!strcmp("angle", key))
5765 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5766 else if (!strcmp("angles", key))
5767 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5768 else if (!strcmp("color", key))
5769 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5770 else if (!strcmp("wait", key))
5771 fadescale = atof(value);
5772 else if (!strcmp("classname", key))
5774 if (!strncmp(value, "light", 5))
5777 if (!strcmp(value, "light_fluoro"))
5782 overridecolor[0] = 1;
5783 overridecolor[1] = 1;
5784 overridecolor[2] = 1;
5786 if (!strcmp(value, "light_fluorospark"))
5791 overridecolor[0] = 1;
5792 overridecolor[1] = 1;
5793 overridecolor[2] = 1;
5795 if (!strcmp(value, "light_globe"))
5800 overridecolor[0] = 1;
5801 overridecolor[1] = 0.8;
5802 overridecolor[2] = 0.4;
5804 if (!strcmp(value, "light_flame_large_yellow"))
5809 overridecolor[0] = 1;
5810 overridecolor[1] = 0.5;
5811 overridecolor[2] = 0.1;
5813 if (!strcmp(value, "light_flame_small_yellow"))
5818 overridecolor[0] = 1;
5819 overridecolor[1] = 0.5;
5820 overridecolor[2] = 0.1;
5822 if (!strcmp(value, "light_torch_small_white"))
5827 overridecolor[0] = 1;
5828 overridecolor[1] = 0.5;
5829 overridecolor[2] = 0.1;
5831 if (!strcmp(value, "light_torch_small_walltorch"))
5836 overridecolor[0] = 1;
5837 overridecolor[1] = 0.5;
5838 overridecolor[2] = 0.1;
5842 else if (!strcmp("style", key))
5843 style = atoi(value);
5844 else if (!strcmp("skin", key))
5845 skin = (int)atof(value);
5846 else if (!strcmp("pflags", key))
5847 pflags = (int)atof(value);
5848 //else if (!strcmp("effects", key))
5849 // effects = (int)atof(value);
5850 else if (cl.worldmodel->type == mod_brushq3)
5852 if (!strcmp("scale", key))
5853 lightscale = atof(value);
5854 if (!strcmp("fade", key))
5855 fadescale = atof(value);
5860 if (lightscale <= 0)
5864 if (color[0] == color[1] && color[0] == color[2])
5866 color[0] *= overridecolor[0];
5867 color[1] *= overridecolor[1];
5868 color[2] *= overridecolor[2];
5870 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5871 color[0] = color[0] * light[0];
5872 color[1] = color[1] * light[1];
5873 color[2] = color[2] * light[2];
5876 case LIGHTTYPE_MINUSX:
5878 case LIGHTTYPE_RECIPX:
5880 VectorScale(color, (1.0f / 16.0f), color);
5882 case LIGHTTYPE_RECIPXX:
5884 VectorScale(color, (1.0f / 16.0f), color);
5887 case LIGHTTYPE_NONE:
5891 case LIGHTTYPE_MINUSXX:
5894 VectorAdd(origin, originhack, origin);
5896 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5899 Mem_Free(entfiledata);
5903 void R_Shadow_SetCursorLocationForView(void)
5906 vec3_t dest, endpos;
5908 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5909 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5910 if (trace.fraction < 1)
5912 dist = trace.fraction * r_editlights_cursordistance.value;
5913 push = r_editlights_cursorpushback.value;
5917 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5918 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5922 VectorClear( endpos );
5924 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5925 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5926 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5929 void R_Shadow_UpdateWorldLightSelection(void)
5931 if (r_editlights.integer)
5933 R_Shadow_SetCursorLocationForView();
5934 R_Shadow_SelectLightInView();
5937 R_Shadow_SelectLight(NULL);
5940 void R_Shadow_EditLights_Clear_f(void)
5942 R_Shadow_ClearWorldLights();
5945 void R_Shadow_EditLights_Reload_f(void)
5949 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5950 R_Shadow_ClearWorldLights();
5951 R_Shadow_LoadWorldLights();
5952 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5954 R_Shadow_LoadLightsFile();
5955 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5956 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5960 void R_Shadow_EditLights_Save_f(void)
5964 R_Shadow_SaveWorldLights();
5967 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5969 R_Shadow_ClearWorldLights();
5970 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5973 void R_Shadow_EditLights_ImportLightsFile_f(void)
5975 R_Shadow_ClearWorldLights();
5976 R_Shadow_LoadLightsFile();
5979 void R_Shadow_EditLights_Spawn_f(void)
5982 if (!r_editlights.integer)
5984 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5987 if (Cmd_Argc() != 1)
5989 Con_Print("r_editlights_spawn does not take parameters\n");
5992 color[0] = color[1] = color[2] = 1;
5993 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5996 void R_Shadow_EditLights_Edit_f(void)
5998 vec3_t origin, angles, color;
5999 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6000 int style, shadows, flags, normalmode, realtimemode;
6001 char cubemapname[MAX_INPUTLINE];
6002 if (!r_editlights.integer)
6004 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6007 if (!r_shadow_selectedlight)
6009 Con_Print("No selected light.\n");
6012 VectorCopy(r_shadow_selectedlight->origin, origin);
6013 VectorCopy(r_shadow_selectedlight->angles, angles);
6014 VectorCopy(r_shadow_selectedlight->color, color);
6015 radius = r_shadow_selectedlight->radius;
6016 style = r_shadow_selectedlight->style;
6017 if (r_shadow_selectedlight->cubemapname)
6018 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6021 shadows = r_shadow_selectedlight->shadow;
6022 corona = r_shadow_selectedlight->corona;
6023 coronasizescale = r_shadow_selectedlight->coronasizescale;
6024 ambientscale = r_shadow_selectedlight->ambientscale;
6025 diffusescale = r_shadow_selectedlight->diffusescale;
6026 specularscale = r_shadow_selectedlight->specularscale;
6027 flags = r_shadow_selectedlight->flags;
6028 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6029 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6030 if (!strcmp(Cmd_Argv(1), "origin"))
6032 if (Cmd_Argc() != 5)
6034 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6037 origin[0] = atof(Cmd_Argv(2));
6038 origin[1] = atof(Cmd_Argv(3));
6039 origin[2] = atof(Cmd_Argv(4));
6041 else if (!strcmp(Cmd_Argv(1), "originx"))
6043 if (Cmd_Argc() != 3)
6045 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6048 origin[0] = atof(Cmd_Argv(2));
6050 else if (!strcmp(Cmd_Argv(1), "originy"))
6052 if (Cmd_Argc() != 3)
6054 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6057 origin[1] = atof(Cmd_Argv(2));
6059 else if (!strcmp(Cmd_Argv(1), "originz"))
6061 if (Cmd_Argc() != 3)
6063 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6066 origin[2] = atof(Cmd_Argv(2));
6068 else if (!strcmp(Cmd_Argv(1), "move"))
6070 if (Cmd_Argc() != 5)
6072 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6075 origin[0] += atof(Cmd_Argv(2));
6076 origin[1] += atof(Cmd_Argv(3));
6077 origin[2] += atof(Cmd_Argv(4));
6079 else if (!strcmp(Cmd_Argv(1), "movex"))
6081 if (Cmd_Argc() != 3)
6083 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6086 origin[0] += atof(Cmd_Argv(2));
6088 else if (!strcmp(Cmd_Argv(1), "movey"))
6090 if (Cmd_Argc() != 3)
6092 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6095 origin[1] += atof(Cmd_Argv(2));
6097 else if (!strcmp(Cmd_Argv(1), "movez"))
6099 if (Cmd_Argc() != 3)
6101 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6104 origin[2] += atof(Cmd_Argv(2));
6106 else if (!strcmp(Cmd_Argv(1), "angles"))
6108 if (Cmd_Argc() != 5)
6110 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6113 angles[0] = atof(Cmd_Argv(2));
6114 angles[1] = atof(Cmd_Argv(3));
6115 angles[2] = atof(Cmd_Argv(4));
6117 else if (!strcmp(Cmd_Argv(1), "anglesx"))
6119 if (Cmd_Argc() != 3)
6121 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6124 angles[0] = atof(Cmd_Argv(2));
6126 else if (!strcmp(Cmd_Argv(1), "anglesy"))
6128 if (Cmd_Argc() != 3)
6130 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6133 angles[1] = atof(Cmd_Argv(2));
6135 else if (!strcmp(Cmd_Argv(1), "anglesz"))
6137 if (Cmd_Argc() != 3)
6139 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6142 angles[2] = atof(Cmd_Argv(2));
6144 else if (!strcmp(Cmd_Argv(1), "color"))
6146 if (Cmd_Argc() != 5)
6148 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
6151 color[0] = atof(Cmd_Argv(2));
6152 color[1] = atof(Cmd_Argv(3));
6153 color[2] = atof(Cmd_Argv(4));
6155 else if (!strcmp(Cmd_Argv(1), "radius"))
6157 if (Cmd_Argc() != 3)
6159 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6162 radius = atof(Cmd_Argv(2));
6164 else if (!strcmp(Cmd_Argv(1), "colorscale"))
6166 if (Cmd_Argc() == 3)
6168 double scale = atof(Cmd_Argv(2));
6175 if (Cmd_Argc() != 5)
6177 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
6180 color[0] *= atof(Cmd_Argv(2));
6181 color[1] *= atof(Cmd_Argv(3));
6182 color[2] *= atof(Cmd_Argv(4));
6185 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
6187 if (Cmd_Argc() != 3)
6189 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6192 radius *= atof(Cmd_Argv(2));
6194 else if (!strcmp(Cmd_Argv(1), "style"))
6196 if (Cmd_Argc() != 3)
6198 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6201 style = atoi(Cmd_Argv(2));
6203 else if (!strcmp(Cmd_Argv(1), "cubemap"))
6207 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6210 if (Cmd_Argc() == 3)
6211 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
6215 else if (!strcmp(Cmd_Argv(1), "shadows"))
6217 if (Cmd_Argc() != 3)
6219 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6222 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6224 else if (!strcmp(Cmd_Argv(1), "corona"))
6226 if (Cmd_Argc() != 3)
6228 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6231 corona = atof(Cmd_Argv(2));
6233 else if (!strcmp(Cmd_Argv(1), "coronasize"))
6235 if (Cmd_Argc() != 3)
6237 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6240 coronasizescale = atof(Cmd_Argv(2));
6242 else if (!strcmp(Cmd_Argv(1), "ambient"))
6244 if (Cmd_Argc() != 3)
6246 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6249 ambientscale = atof(Cmd_Argv(2));
6251 else if (!strcmp(Cmd_Argv(1), "diffuse"))
6253 if (Cmd_Argc() != 3)
6255 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6258 diffusescale = atof(Cmd_Argv(2));
6260 else if (!strcmp(Cmd_Argv(1), "specular"))
6262 if (Cmd_Argc() != 3)
6264 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6267 specularscale = atof(Cmd_Argv(2));
6269 else if (!strcmp(Cmd_Argv(1), "normalmode"))
6271 if (Cmd_Argc() != 3)
6273 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6276 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6278 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
6280 if (Cmd_Argc() != 3)
6282 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6285 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6289 Con_Print("usage: r_editlights_edit [property] [value]\n");
6290 Con_Print("Selected light's properties:\n");
6291 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6292 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6293 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6294 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
6295 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
6296 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
6297 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
6298 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
6299 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
6300 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
6301 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
6302 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
6303 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
6304 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
6307 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
6308 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6311 void R_Shadow_EditLights_EditAll_f(void)
6314 dlight_t *light, *oldselected;
6317 if (!r_editlights.integer)
6319 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
6323 oldselected = r_shadow_selectedlight;
6324 // EditLights doesn't seem to have a "remove" command or something so:
6325 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6326 for (lightindex = 0;lightindex < range;lightindex++)
6328 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6331 R_Shadow_SelectLight(light);
6332 R_Shadow_EditLights_Edit_f();
6334 // return to old selected (to not mess editing once selection is locked)
6335 R_Shadow_SelectLight(oldselected);
6338 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
6340 int lightnumber, lightcount;
6341 size_t lightindex, range;
6345 if (!r_editlights.integer)
6347 x = vid_conwidth.value - 240;
6349 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
6352 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6353 for (lightindex = 0;lightindex < range;lightindex++)
6355 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6358 if (light == r_shadow_selectedlight)
6359 lightnumber = lightindex;
6362 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;
6363 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;
6365 if (r_shadow_selectedlight == NULL)
6367 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;
6368 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;
6369 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;
6370 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;
6371 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;
6372 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;
6373 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;
6374 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;
6375 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;
6376 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;
6377 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;
6378 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;
6379 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;
6380 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;
6381 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;
6384 void R_Shadow_EditLights_ToggleShadow_f(void)
6386 if (!r_editlights.integer)
6388 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6391 if (!r_shadow_selectedlight)
6393 Con_Print("No selected light.\n");
6396 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);
6399 void R_Shadow_EditLights_ToggleCorona_f(void)
6401 if (!r_editlights.integer)
6403 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6406 if (!r_shadow_selectedlight)
6408 Con_Print("No selected light.\n");
6411 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);
6414 void R_Shadow_EditLights_Remove_f(void)
6416 if (!r_editlights.integer)
6418 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
6421 if (!r_shadow_selectedlight)
6423 Con_Print("No selected light.\n");
6426 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
6427 r_shadow_selectedlight = NULL;
6430 void R_Shadow_EditLights_Help_f(void)
6433 "Documentation on r_editlights system:\n"
6435 "r_editlights : enable/disable editing mode\n"
6436 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
6437 "r_editlights_cursorpushback : push back cursor this far from surface\n"
6438 "r_editlights_cursorpushoff : push cursor off surface this far\n"
6439 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
6440 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
6442 "r_editlights_help : this help\n"
6443 "r_editlights_clear : remove all lights\n"
6444 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
6445 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
6446 "r_editlights_save : save to .rtlights file\n"
6447 "r_editlights_spawn : create a light with default settings\n"
6448 "r_editlights_edit command : edit selected light - more documentation below\n"
6449 "r_editlights_remove : remove selected light\n"
6450 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
6451 "r_editlights_importlightentitiesfrommap : reload light entities\n"
6452 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
6454 "origin x y z : set light location\n"
6455 "originx x: set x component of light location\n"
6456 "originy y: set y component of light location\n"
6457 "originz z: set z component of light location\n"
6458 "move x y z : adjust light location\n"
6459 "movex x: adjust x component of light location\n"
6460 "movey y: adjust y component of light location\n"
6461 "movez z: adjust z component of light location\n"
6462 "angles x y z : set light angles\n"
6463 "anglesx x: set x component of light angles\n"
6464 "anglesy y: set y component of light angles\n"
6465 "anglesz z: set z component of light angles\n"
6466 "color r g b : set color of light (can be brighter than 1 1 1)\n"
6467 "radius radius : set radius (size) of light\n"
6468 "colorscale grey : multiply color of light (1 does nothing)\n"
6469 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
6470 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
6471 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
6472 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
6473 "cubemap basename : set filter cubemap of light (not yet supported)\n"
6474 "shadows 1/0 : turn on/off shadows\n"
6475 "corona n : set corona intensity\n"
6476 "coronasize n : set corona size (0-1)\n"
6477 "ambient n : set ambient intensity (0-1)\n"
6478 "diffuse n : set diffuse intensity (0-1)\n"
6479 "specular n : set specular intensity (0-1)\n"
6480 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6481 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6482 "<nothing> : print light properties to console\n"
6486 void R_Shadow_EditLights_CopyInfo_f(void)
6488 if (!r_editlights.integer)
6490 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
6493 if (!r_shadow_selectedlight)
6495 Con_Print("No selected light.\n");
6498 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6499 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6500 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6501 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6502 if (r_shadow_selectedlight->cubemapname)
6503 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6505 r_shadow_bufferlight.cubemapname[0] = 0;
6506 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6507 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6508 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6509 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6510 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6511 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6512 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6515 void R_Shadow_EditLights_PasteInfo_f(void)
6517 if (!r_editlights.integer)
6519 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6522 if (!r_shadow_selectedlight)
6524 Con_Print("No selected light.\n");
6527 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);
6530 void R_Shadow_EditLights_Lock_f(void)
6532 if (!r_editlights.integer)
6534 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6537 if (r_editlights_lockcursor)
6539 r_editlights_lockcursor = false;
6542 if (!r_shadow_selectedlight)
6544 Con_Print("No selected light to lock on.\n");
6547 r_editlights_lockcursor = true;
6550 void R_Shadow_EditLights_Init(void)
6552 Cvar_RegisterVariable(&r_editlights);
6553 Cvar_RegisterVariable(&r_editlights_cursordistance);
6554 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6555 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6556 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6557 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6558 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6559 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6560 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)");
6561 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6562 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6563 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6564 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)");
6565 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6566 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6567 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6568 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6569 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6570 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6571 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)");
6572 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6578 =============================================================================
6582 =============================================================================
6585 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
6587 int i, numlights, flag;
6590 float relativepoint[3];
6599 if (r_fullbright.integer)
6601 VectorSet(ambient, 1, 1, 1);
6602 VectorClear(diffuse);
6603 VectorClear(lightdir);
6607 if (flags & LP_LIGHTMAP)
6609 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6610 VectorClear(diffuse);
6611 VectorClear(lightdir);
6612 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6613 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
6617 memset(sample, 0, sizeof(sample));
6618 VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6620 if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6623 VectorClear(tempambient);
6625 VectorClear(relativepoint);
6626 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6627 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
6628 VectorScale(color, r_refdef.lightmapintensity, color);
6629 VectorAdd(sample, tempambient, sample);
6630 VectorMA(sample , 0.5f , color, sample );
6631 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6632 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6633 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6634 // calculate a weighted average light direction as well
6635 intensity = VectorLength(color);
6636 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6639 if (flags & LP_RTWORLD)
6641 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6642 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6643 for (i = 0; i < numlights; i++)
6645 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6648 light = &dlight->rtlight;
6649 if (!(light->flags & flag))
6652 lightradius2 = light->radius * light->radius;
6653 VectorSubtract(light->shadoworigin, p, relativepoint);
6654 dist2 = VectorLength2(relativepoint);
6655 if (dist2 >= lightradius2)
6657 dist = sqrt(dist2) / light->radius;
6658 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6659 if (intensity <= 0.0f)
6661 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
6663 // scale down intensity to add to both ambient and diffuse
6664 //intensity *= 0.5f;
6665 VectorNormalize(relativepoint);
6666 VectorScale(light->currentcolor, intensity, color);
6667 VectorMA(sample , 0.5f , color, sample );
6668 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6669 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6670 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6671 // calculate a weighted average light direction as well
6672 intensity *= VectorLength(color);
6673 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6677 if (flags & LP_DYNLIGHT)
6680 for (i = 0;i < r_refdef.scene.numlights;i++)
6682 light = r_refdef.scene.lights[i];
6684 lightradius2 = light->radius * light->radius;
6685 VectorSubtract(light->shadoworigin, p, relativepoint);
6686 dist2 = VectorLength2(relativepoint);
6687 if (dist2 >= lightradius2)
6689 dist = sqrt(dist2) / light->radius;
6690 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6691 if (intensity <= 0.0f)
6693 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
6695 // scale down intensity to add to both ambient and diffuse
6696 //intensity *= 0.5f;
6697 VectorNormalize(relativepoint);
6698 VectorScale(light->currentcolor, intensity, color);
6699 VectorMA(sample , 0.5f , color, sample );
6700 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6701 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6702 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6703 // calculate a weighted average light direction as well
6704 intensity *= VectorLength(color);
6705 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6709 // calculate the direction we'll use to reduce the sample to a directional light source
6710 VectorCopy(sample + 12, dir);
6711 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
6712 VectorNormalize(dir);
6713 // extract the diffuse color along the chosen direction and scale it
6714 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
6715 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
6716 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
6717 // subtract some of diffuse from ambient
6718 VectorMA(sample, -0.333f, diffuse, ambient);
6719 // store the normalized lightdir
6720 VectorCopy(dir, lightdir);