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 if (gamemode == GAME_TENEBRAE)
748 Cvar_SetValue("r_shadow_gloss", 2);
749 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
751 R_Shadow_EditLights_Init();
752 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
753 maxshadowtriangles = 0;
754 shadowelements = NULL;
755 maxshadowvertices = 0;
756 shadowvertex3f = NULL;
764 shadowmarklist = NULL;
769 shadowsideslist = NULL;
770 r_shadow_buffer_numleafpvsbytes = 0;
771 r_shadow_buffer_visitingleafpvs = NULL;
772 r_shadow_buffer_leafpvs = NULL;
773 r_shadow_buffer_leaflist = NULL;
774 r_shadow_buffer_numsurfacepvsbytes = 0;
775 r_shadow_buffer_surfacepvs = NULL;
776 r_shadow_buffer_surfacelist = NULL;
777 r_shadow_buffer_surfacesides = NULL;
778 r_shadow_buffer_shadowtrispvs = NULL;
779 r_shadow_buffer_lighttrispvs = NULL;
780 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
783 matrix4x4_t matrix_attenuationxyz =
786 {0.5, 0.0, 0.0, 0.5},
787 {0.0, 0.5, 0.0, 0.5},
788 {0.0, 0.0, 0.5, 0.5},
793 matrix4x4_t matrix_attenuationz =
796 {0.0, 0.0, 0.5, 0.5},
797 {0.0, 0.0, 0.0, 0.5},
798 {0.0, 0.0, 0.0, 0.5},
803 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
805 numvertices = ((numvertices + 255) & ~255) * vertscale;
806 numtriangles = ((numtriangles + 255) & ~255) * triscale;
807 // make sure shadowelements is big enough for this volume
808 if (maxshadowtriangles < numtriangles)
810 maxshadowtriangles = numtriangles;
812 Mem_Free(shadowelements);
813 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
815 // make sure shadowvertex3f is big enough for this volume
816 if (maxshadowvertices < numvertices)
818 maxshadowvertices = numvertices;
820 Mem_Free(shadowvertex3f);
821 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
825 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
827 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
828 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
829 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
830 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
831 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
833 if (r_shadow_buffer_visitingleafpvs)
834 Mem_Free(r_shadow_buffer_visitingleafpvs);
835 if (r_shadow_buffer_leafpvs)
836 Mem_Free(r_shadow_buffer_leafpvs);
837 if (r_shadow_buffer_leaflist)
838 Mem_Free(r_shadow_buffer_leaflist);
839 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
840 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
841 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
842 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
844 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
846 if (r_shadow_buffer_surfacepvs)
847 Mem_Free(r_shadow_buffer_surfacepvs);
848 if (r_shadow_buffer_surfacelist)
849 Mem_Free(r_shadow_buffer_surfacelist);
850 if (r_shadow_buffer_surfacesides)
851 Mem_Free(r_shadow_buffer_surfacesides);
852 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
853 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
854 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
855 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
857 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
859 if (r_shadow_buffer_shadowtrispvs)
860 Mem_Free(r_shadow_buffer_shadowtrispvs);
861 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
862 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
864 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
866 if (r_shadow_buffer_lighttrispvs)
867 Mem_Free(r_shadow_buffer_lighttrispvs);
868 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
869 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
873 void R_Shadow_PrepareShadowMark(int numtris)
875 // make sure shadowmark is big enough for this volume
876 if (maxshadowmark < numtris)
878 maxshadowmark = numtris;
880 Mem_Free(shadowmark);
882 Mem_Free(shadowmarklist);
883 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
884 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
888 // if shadowmarkcount wrapped we clear the array and adjust accordingly
889 if (shadowmarkcount == 0)
892 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
897 void R_Shadow_PrepareShadowSides(int numtris)
899 if (maxshadowsides < numtris)
901 maxshadowsides = numtris;
903 Mem_Free(shadowsides);
905 Mem_Free(shadowsideslist);
906 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
907 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
912 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)
915 int outtriangles = 0, outvertices = 0;
918 float ratio, direction[3], projectvector[3];
920 if (projectdirection)
921 VectorScale(projectdirection, projectdistance, projectvector);
923 VectorClear(projectvector);
925 // create the vertices
926 if (projectdirection)
928 for (i = 0;i < numshadowmarktris;i++)
930 element = inelement3i + shadowmarktris[i] * 3;
931 for (j = 0;j < 3;j++)
933 if (vertexupdate[element[j]] != vertexupdatenum)
935 vertexupdate[element[j]] = vertexupdatenum;
936 vertexremap[element[j]] = outvertices;
937 vertex = invertex3f + element[j] * 3;
938 // project one copy of the vertex according to projectvector
939 VectorCopy(vertex, outvertex3f);
940 VectorAdd(vertex, projectvector, (outvertex3f + 3));
949 for (i = 0;i < numshadowmarktris;i++)
951 element = inelement3i + shadowmarktris[i] * 3;
952 for (j = 0;j < 3;j++)
954 if (vertexupdate[element[j]] != vertexupdatenum)
956 vertexupdate[element[j]] = vertexupdatenum;
957 vertexremap[element[j]] = outvertices;
958 vertex = invertex3f + element[j] * 3;
959 // project one copy of the vertex to the sphere radius of the light
960 // (FIXME: would projecting it to the light box be better?)
961 VectorSubtract(vertex, projectorigin, direction);
962 ratio = projectdistance / VectorLength(direction);
963 VectorCopy(vertex, outvertex3f);
964 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
972 if (r_shadow_frontsidecasting.integer)
974 for (i = 0;i < numshadowmarktris;i++)
976 int remappedelement[3];
978 const int *neighbortriangle;
980 markindex = shadowmarktris[i] * 3;
981 element = inelement3i + markindex;
982 neighbortriangle = inneighbor3i + markindex;
983 // output the front and back triangles
984 outelement3i[0] = vertexremap[element[0]];
985 outelement3i[1] = vertexremap[element[1]];
986 outelement3i[2] = vertexremap[element[2]];
987 outelement3i[3] = vertexremap[element[2]] + 1;
988 outelement3i[4] = vertexremap[element[1]] + 1;
989 outelement3i[5] = vertexremap[element[0]] + 1;
993 // output the sides (facing outward from this triangle)
994 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
996 remappedelement[0] = vertexremap[element[0]];
997 remappedelement[1] = vertexremap[element[1]];
998 outelement3i[0] = remappedelement[1];
999 outelement3i[1] = remappedelement[0];
1000 outelement3i[2] = remappedelement[0] + 1;
1001 outelement3i[3] = remappedelement[1];
1002 outelement3i[4] = remappedelement[0] + 1;
1003 outelement3i[5] = remappedelement[1] + 1;
1008 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1010 remappedelement[1] = vertexremap[element[1]];
1011 remappedelement[2] = vertexremap[element[2]];
1012 outelement3i[0] = remappedelement[2];
1013 outelement3i[1] = remappedelement[1];
1014 outelement3i[2] = remappedelement[1] + 1;
1015 outelement3i[3] = remappedelement[2];
1016 outelement3i[4] = remappedelement[1] + 1;
1017 outelement3i[5] = remappedelement[2] + 1;
1022 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1024 remappedelement[0] = vertexremap[element[0]];
1025 remappedelement[2] = vertexremap[element[2]];
1026 outelement3i[0] = remappedelement[0];
1027 outelement3i[1] = remappedelement[2];
1028 outelement3i[2] = remappedelement[2] + 1;
1029 outelement3i[3] = remappedelement[0];
1030 outelement3i[4] = remappedelement[2] + 1;
1031 outelement3i[5] = remappedelement[0] + 1;
1040 for (i = 0;i < numshadowmarktris;i++)
1042 int remappedelement[3];
1044 const int *neighbortriangle;
1046 markindex = shadowmarktris[i] * 3;
1047 element = inelement3i + markindex;
1048 neighbortriangle = inneighbor3i + markindex;
1049 // output the front and back triangles
1050 outelement3i[0] = vertexremap[element[2]];
1051 outelement3i[1] = vertexremap[element[1]];
1052 outelement3i[2] = vertexremap[element[0]];
1053 outelement3i[3] = vertexremap[element[0]] + 1;
1054 outelement3i[4] = vertexremap[element[1]] + 1;
1055 outelement3i[5] = vertexremap[element[2]] + 1;
1059 // output the sides (facing outward from this triangle)
1060 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1062 remappedelement[0] = vertexremap[element[0]];
1063 remappedelement[1] = vertexremap[element[1]];
1064 outelement3i[0] = remappedelement[0];
1065 outelement3i[1] = remappedelement[1];
1066 outelement3i[2] = remappedelement[1] + 1;
1067 outelement3i[3] = remappedelement[0];
1068 outelement3i[4] = remappedelement[1] + 1;
1069 outelement3i[5] = remappedelement[0] + 1;
1074 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1076 remappedelement[1] = vertexremap[element[1]];
1077 remappedelement[2] = vertexremap[element[2]];
1078 outelement3i[0] = remappedelement[1];
1079 outelement3i[1] = remappedelement[2];
1080 outelement3i[2] = remappedelement[2] + 1;
1081 outelement3i[3] = remappedelement[1];
1082 outelement3i[4] = remappedelement[2] + 1;
1083 outelement3i[5] = remappedelement[1] + 1;
1088 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1090 remappedelement[0] = vertexremap[element[0]];
1091 remappedelement[2] = vertexremap[element[2]];
1092 outelement3i[0] = remappedelement[2];
1093 outelement3i[1] = remappedelement[0];
1094 outelement3i[2] = remappedelement[0] + 1;
1095 outelement3i[3] = remappedelement[2];
1096 outelement3i[4] = remappedelement[0] + 1;
1097 outelement3i[5] = remappedelement[2] + 1;
1105 *outnumvertices = outvertices;
1106 return outtriangles;
1109 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)
1112 int outtriangles = 0, outvertices = 0;
1114 const float *vertex;
1115 float ratio, direction[3], projectvector[3];
1118 if (projectdirection)
1119 VectorScale(projectdirection, projectdistance, projectvector);
1121 VectorClear(projectvector);
1123 for (i = 0;i < numshadowmarktris;i++)
1125 int remappedelement[3];
1127 const int *neighbortriangle;
1129 markindex = shadowmarktris[i] * 3;
1130 neighbortriangle = inneighbor3i + markindex;
1131 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1132 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1133 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1134 if (side[0] + side[1] + side[2] == 0)
1138 element = inelement3i + markindex;
1140 // create the vertices
1141 for (j = 0;j < 3;j++)
1143 if (side[j] + side[j+1] == 0)
1146 if (vertexupdate[k] != vertexupdatenum)
1148 vertexupdate[k] = vertexupdatenum;
1149 vertexremap[k] = outvertices;
1150 vertex = invertex3f + k * 3;
1151 VectorCopy(vertex, outvertex3f);
1152 if (projectdirection)
1154 // project one copy of the vertex according to projectvector
1155 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1159 // project one copy of the vertex to the sphere radius of the light
1160 // (FIXME: would projecting it to the light box be better?)
1161 VectorSubtract(vertex, projectorigin, direction);
1162 ratio = projectdistance / VectorLength(direction);
1163 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1170 // output the sides (facing outward from this triangle)
1173 remappedelement[0] = vertexremap[element[0]];
1174 remappedelement[1] = vertexremap[element[1]];
1175 outelement3i[0] = remappedelement[1];
1176 outelement3i[1] = remappedelement[0];
1177 outelement3i[2] = remappedelement[0] + 1;
1178 outelement3i[3] = remappedelement[1];
1179 outelement3i[4] = remappedelement[0] + 1;
1180 outelement3i[5] = remappedelement[1] + 1;
1187 remappedelement[1] = vertexremap[element[1]];
1188 remappedelement[2] = vertexremap[element[2]];
1189 outelement3i[0] = remappedelement[2];
1190 outelement3i[1] = remappedelement[1];
1191 outelement3i[2] = remappedelement[1] + 1;
1192 outelement3i[3] = remappedelement[2];
1193 outelement3i[4] = remappedelement[1] + 1;
1194 outelement3i[5] = remappedelement[2] + 1;
1201 remappedelement[0] = vertexremap[element[0]];
1202 remappedelement[2] = vertexremap[element[2]];
1203 outelement3i[0] = remappedelement[0];
1204 outelement3i[1] = remappedelement[2];
1205 outelement3i[2] = remappedelement[2] + 1;
1206 outelement3i[3] = remappedelement[0];
1207 outelement3i[4] = remappedelement[2] + 1;
1208 outelement3i[5] = remappedelement[0] + 1;
1215 *outnumvertices = outvertices;
1216 return outtriangles;
1219 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)
1225 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1227 tend = firsttriangle + numtris;
1228 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1230 // surface box entirely inside light box, no box cull
1231 if (projectdirection)
1233 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1235 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1236 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1237 shadowmarklist[numshadowmark++] = t;
1242 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1243 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1244 shadowmarklist[numshadowmark++] = t;
1249 // surface box not entirely inside light box, cull each triangle
1250 if (projectdirection)
1252 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1254 v[0] = invertex3f + e[0] * 3;
1255 v[1] = invertex3f + e[1] * 3;
1256 v[2] = invertex3f + e[2] * 3;
1257 TriangleNormal(v[0], v[1], v[2], normal);
1258 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1259 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1260 shadowmarklist[numshadowmark++] = t;
1265 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1267 v[0] = invertex3f + e[0] * 3;
1268 v[1] = invertex3f + e[1] * 3;
1269 v[2] = invertex3f + e[2] * 3;
1270 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1271 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1272 shadowmarklist[numshadowmark++] = t;
1278 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1283 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1285 // check if the shadow volume intersects the near plane
1287 // a ray between the eye and light origin may intersect the caster,
1288 // indicating that the shadow may touch the eye location, however we must
1289 // test the near plane (a polygon), not merely the eye location, so it is
1290 // easiest to enlarge the caster bounding shape slightly for this.
1296 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)
1298 int i, tris, outverts;
1299 if (projectdistance < 0.1)
1301 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1304 if (!numverts || !nummarktris)
1306 // make sure shadowelements is big enough for this volume
1307 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1308 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1310 if (maxvertexupdate < numverts)
1312 maxvertexupdate = numverts;
1314 Mem_Free(vertexupdate);
1316 Mem_Free(vertexremap);
1317 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1318 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1319 vertexupdatenum = 0;
1322 if (vertexupdatenum == 0)
1324 vertexupdatenum = 1;
1325 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1326 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1329 for (i = 0;i < nummarktris;i++)
1330 shadowmark[marktris[i]] = shadowmarkcount;
1332 if (r_shadow_compilingrtlight)
1334 // if we're compiling an rtlight, capture the mesh
1335 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1336 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1337 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1338 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1340 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1342 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1343 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1344 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1348 // decide which type of shadow to generate and set stencil mode
1349 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1350 // generate the sides or a solid volume, depending on type
1351 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1352 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1354 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1355 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1356 r_refdef.stats.lights_shadowtriangles += tris;
1357 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1359 // increment stencil if frontface is infront of depthbuffer
1360 GL_CullFace(r_refdef.view.cullface_front);
1361 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1362 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1363 // decrement stencil if backface is infront of depthbuffer
1364 GL_CullFace(r_refdef.view.cullface_back);
1365 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1367 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1369 // decrement stencil if backface is behind depthbuffer
1370 GL_CullFace(r_refdef.view.cullface_front);
1371 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1372 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1373 // increment stencil if frontface is behind depthbuffer
1374 GL_CullFace(r_refdef.view.cullface_back);
1375 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1377 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1378 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1382 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1384 // p1, p2, p3 are in the cubemap's local coordinate system
1385 // bias = border/(size - border)
1388 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1389 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1390 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1391 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1393 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1394 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1395 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1396 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1398 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1399 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1400 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1402 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1403 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1404 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1405 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1407 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1408 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1409 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1410 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1412 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1413 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1414 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1416 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1417 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1418 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1419 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1421 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1422 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1423 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1424 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1426 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1427 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1428 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1433 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1435 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1436 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1439 VectorSubtract(maxs, mins, radius);
1440 VectorScale(radius, 0.5f, radius);
1441 VectorAdd(mins, radius, center);
1442 Matrix4x4_Transform(worldtolight, center, lightcenter);
1443 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1444 VectorSubtract(lightcenter, lightradius, pmin);
1445 VectorAdd(lightcenter, lightradius, pmax);
1447 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1448 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1449 if(ap1 > bias*an1 && ap2 > bias*an2)
1451 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1452 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1453 if(an1 > bias*ap1 && an2 > bias*ap2)
1455 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1456 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1458 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1459 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1460 if(ap1 > bias*an1 && ap2 > bias*an2)
1462 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1463 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1464 if(an1 > bias*ap1 && an2 > bias*ap2)
1466 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1467 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1469 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1470 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1471 if(ap1 > bias*an1 && ap2 > bias*an2)
1473 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1474 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1475 if(an1 > bias*ap1 && an2 > bias*ap2)
1477 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1478 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1483 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1485 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1487 // p is in the cubemap's local coordinate system
1488 // bias = border/(size - border)
1489 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1490 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1491 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1493 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1494 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1495 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1496 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1497 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1498 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1502 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1506 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1507 float scale = (size - 2*border)/size, len;
1508 float bias = border / (float)(size - border), dp, dn, ap, an;
1509 // check if cone enclosing side would cross frustum plane
1510 scale = 2 / (scale*scale + 2);
1511 for (i = 0;i < 5;i++)
1513 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1515 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1516 len = scale*VectorLength2(n);
1517 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1518 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1519 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1521 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1523 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1524 len = scale*VectorLength(n);
1525 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1526 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1527 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1529 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1530 // check if frustum corners/origin cross plane sides
1532 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1533 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1534 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1535 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1536 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1537 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1538 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1539 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1540 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1541 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1542 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1543 for (i = 0;i < 4;i++)
1545 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1546 VectorSubtract(n, p, n);
1547 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1548 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1549 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1550 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1551 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1552 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1553 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1554 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1555 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1558 // finite version, assumes corners are a finite distance from origin dependent on far plane
1559 for (i = 0;i < 5;i++)
1561 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1562 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1563 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1564 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1565 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1566 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1567 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1568 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1569 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1570 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1573 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1576 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)
1584 int mask, surfacemask = 0;
1585 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1587 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1588 tend = firsttriangle + numtris;
1589 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1591 // surface box entirely inside light box, no box cull
1592 if (projectdirection)
1594 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1596 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1597 TriangleNormal(v[0], v[1], v[2], normal);
1598 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1600 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1601 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1602 surfacemask |= mask;
1605 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;
1606 shadowsides[numshadowsides] = mask;
1607 shadowsideslist[numshadowsides++] = t;
1614 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1616 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1617 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1619 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1620 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1621 surfacemask |= mask;
1624 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;
1625 shadowsides[numshadowsides] = mask;
1626 shadowsideslist[numshadowsides++] = t;
1634 // surface box not entirely inside light box, cull each triangle
1635 if (projectdirection)
1637 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1639 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1640 TriangleNormal(v[0], v[1], v[2], normal);
1641 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1642 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1644 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1645 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1646 surfacemask |= mask;
1649 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;
1650 shadowsides[numshadowsides] = mask;
1651 shadowsideslist[numshadowsides++] = t;
1658 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1660 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1661 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1662 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1664 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1665 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1666 surfacemask |= mask;
1669 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;
1670 shadowsides[numshadowsides] = mask;
1671 shadowsideslist[numshadowsides++] = t;
1680 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)
1682 int i, j, outtriangles = 0;
1683 int *outelement3i[6];
1684 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1686 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1687 // make sure shadowelements is big enough for this mesh
1688 if (maxshadowtriangles < outtriangles)
1689 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1691 // compute the offset and size of the separate index lists for each cubemap side
1693 for (i = 0;i < 6;i++)
1695 outelement3i[i] = shadowelements + outtriangles * 3;
1696 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1697 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1698 outtriangles += sidetotals[i];
1701 // gather up the (sparse) triangles into separate index lists for each cubemap side
1702 for (i = 0;i < numsidetris;i++)
1704 const int *element = elements + sidetris[i] * 3;
1705 for (j = 0;j < 6;j++)
1707 if (sides[i] & (1 << j))
1709 outelement3i[j][0] = element[0];
1710 outelement3i[j][1] = element[1];
1711 outelement3i[j][2] = element[2];
1712 outelement3i[j] += 3;
1717 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1720 static void R_Shadow_MakeTextures_MakeCorona(void)
1724 unsigned char pixels[32][32][4];
1725 for (y = 0;y < 32;y++)
1727 dy = (y - 15.5f) * (1.0f / 16.0f);
1728 for (x = 0;x < 32;x++)
1730 dx = (x - 15.5f) * (1.0f / 16.0f);
1731 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1732 a = bound(0, a, 255);
1733 pixels[y][x][0] = a;
1734 pixels[y][x][1] = a;
1735 pixels[y][x][2] = a;
1736 pixels[y][x][3] = 255;
1739 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1742 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1744 float dist = sqrt(x*x+y*y+z*z);
1745 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1746 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1747 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1750 static void R_Shadow_MakeTextures(void)
1753 float intensity, dist;
1755 R_Shadow_FreeShadowMaps();
1756 R_FreeTexturePool(&r_shadow_texturepool);
1757 r_shadow_texturepool = R_AllocTexturePool();
1758 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1759 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1760 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1761 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1762 for (x = 0;x <= ATTENTABLESIZE;x++)
1764 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1765 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1766 r_shadow_attentable[x] = bound(0, intensity, 1);
1768 // 1D gradient texture
1769 for (x = 0;x < ATTEN1DSIZE;x++)
1770 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1771 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1772 // 2D circle texture
1773 for (y = 0;y < ATTEN2DSIZE;y++)
1774 for (x = 0;x < ATTEN2DSIZE;x++)
1775 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);
1776 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1777 // 3D sphere texture
1778 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1780 for (z = 0;z < ATTEN3DSIZE;z++)
1781 for (y = 0;y < ATTEN3DSIZE;y++)
1782 for (x = 0;x < ATTEN3DSIZE;x++)
1783 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));
1784 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);
1787 r_shadow_attenuation3dtexture = NULL;
1790 R_Shadow_MakeTextures_MakeCorona();
1792 // Editor light sprites
1793 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1810 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1811 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1828 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1829 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1846 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1847 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1864 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1865 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1882 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1883 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1900 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1903 void R_Shadow_ValidateCvars(void)
1905 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1906 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1907 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1908 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1909 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1910 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1913 void R_Shadow_RenderMode_Begin(void)
1919 R_Shadow_ValidateCvars();
1921 if (!r_shadow_attenuation2dtexture
1922 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1923 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1924 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1925 R_Shadow_MakeTextures();
1928 R_Mesh_ResetTextureState();
1929 GL_BlendFunc(GL_ONE, GL_ZERO);
1930 GL_DepthRange(0, 1);
1931 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1933 GL_DepthMask(false);
1934 GL_Color(0, 0, 0, 1);
1935 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1937 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1939 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1941 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1942 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1944 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1946 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1947 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1951 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1952 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1955 switch(vid.renderpath)
1957 case RENDERPATH_GL20:
1958 case RENDERPATH_D3D9:
1959 case RENDERPATH_D3D10:
1960 case RENDERPATH_D3D11:
1961 case RENDERPATH_SOFT:
1962 case RENDERPATH_GLES2:
1963 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1965 case RENDERPATH_GL13:
1966 case RENDERPATH_GL11:
1967 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1968 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1969 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1970 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1971 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1972 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1974 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1980 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1981 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1982 r_shadow_drawbuffer = drawbuffer;
1983 r_shadow_readbuffer = readbuffer;
1985 r_shadow_cullface_front = r_refdef.view.cullface_front;
1986 r_shadow_cullface_back = r_refdef.view.cullface_back;
1989 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1991 rsurface.rtlight = rtlight;
1994 void R_Shadow_RenderMode_Reset(void)
1996 R_Mesh_ResetRenderTargets();
1997 R_SetViewport(&r_refdef.view.viewport);
1998 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1999 R_Mesh_ResetTextureState();
2000 GL_DepthRange(0, 1);
2002 GL_DepthMask(false);
2003 GL_DepthFunc(GL_LEQUAL);
2004 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2005 r_refdef.view.cullface_front = r_shadow_cullface_front;
2006 r_refdef.view.cullface_back = r_shadow_cullface_back;
2007 GL_CullFace(r_refdef.view.cullface_back);
2008 GL_Color(1, 1, 1, 1);
2009 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2010 GL_BlendFunc(GL_ONE, GL_ZERO);
2011 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
2012 r_shadow_usingshadowmap2d = false;
2013 r_shadow_usingshadowmaportho = false;
2014 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2017 void R_Shadow_ClearStencil(void)
2019 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2020 r_refdef.stats.lights_clears++;
2023 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2025 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2026 if (r_shadow_rendermode == mode)
2028 R_Shadow_RenderMode_Reset();
2029 GL_DepthFunc(GL_LESS);
2030 GL_ColorMask(0, 0, 0, 0);
2031 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2032 GL_CullFace(GL_NONE);
2033 R_SetupShader_DepthOrShadow();
2034 r_shadow_rendermode = mode;
2039 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2040 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2041 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2043 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2044 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2045 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2050 static void R_Shadow_MakeVSDCT(void)
2052 // maps to a 2x3 texture rectangle with normalized coordinates
2057 // stores abs(dir.xy), offset.xy/2.5
2058 unsigned char data[4*6] =
2060 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2061 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2062 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2063 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2064 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2065 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2067 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2070 static void R_Shadow_MakeShadowMap(int side, int size)
2072 switch (r_shadow_shadowmode)
2074 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2075 if (r_shadow_shadowmap2dtexture) return;
2076 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);
2077 r_shadow_shadowmap2dcolortexture = NULL;
2078 switch(vid.renderpath)
2081 case RENDERPATH_D3D9:
2082 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);
2083 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2087 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, NULL, NULL, NULL, NULL);
2095 // render depth into the fbo, do not render color at all
2096 // validate the fbo now
2100 qglDrawBuffer(GL_NONE);CHECKGLERROR
2101 qglReadBuffer(GL_NONE);CHECKGLERROR
2102 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2103 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2105 Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2106 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2107 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2112 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2114 float nearclip, farclip, bias;
2115 r_viewport_t viewport;
2118 float clearcolor[4];
2119 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2121 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2122 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2123 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2124 r_shadow_shadowmapside = side;
2125 r_shadow_shadowmapsize = size;
2127 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2128 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2129 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2130 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2132 // complex unrolled cube approach (more flexible)
2133 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2134 R_Shadow_MakeVSDCT();
2135 if (!r_shadow_shadowmap2dtexture)
2136 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2137 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2138 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2139 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2140 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2142 R_Mesh_ResetTextureState();
2143 R_Mesh_ResetRenderTargets();
2144 R_Shadow_RenderMode_Reset();
2147 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2148 R_SetupShader_DepthOrShadow();
2151 R_SetupShader_ShowDepth();
2152 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2157 R_SetViewport(&viewport);
2158 flipped = (side & 1) ^ (side >> 2);
2159 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2160 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2161 switch(vid.renderpath)
2163 case RENDERPATH_GL11:
2164 case RENDERPATH_GL13:
2165 case RENDERPATH_GL20:
2166 case RENDERPATH_SOFT:
2167 case RENDERPATH_GLES2:
2168 GL_CullFace(r_refdef.view.cullface_back);
2169 // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
2170 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2172 // get tightest scissor rectangle that encloses all viewports in the clear mask
2173 int x1 = clear & 0x15 ? 0 : size;
2174 int x2 = clear & 0x2A ? 2 * size : size;
2175 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2176 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2177 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2178 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2180 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2182 case RENDERPATH_D3D9:
2183 case RENDERPATH_D3D10:
2184 case RENDERPATH_D3D11:
2185 Vector4Set(clearcolor, 1,1,1,1);
2186 // completely different meaning than in OpenGL path
2187 r_shadow_shadowmap_parameters[1] = 0;
2188 r_shadow_shadowmap_parameters[3] = -bias;
2189 // we invert the cull mode because we flip the projection matrix
2190 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2191 GL_CullFace(r_refdef.view.cullface_front);
2192 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2193 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2194 if (r_shadow_shadowmapsampler)
2196 GL_ColorMask(0,0,0,0);
2198 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2202 GL_ColorMask(1,1,1,1);
2204 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2210 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2212 R_Mesh_ResetTextureState();
2213 R_Mesh_ResetRenderTargets();
2216 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2217 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2218 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2219 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2221 R_Shadow_RenderMode_Reset();
2222 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2224 GL_DepthFunc(GL_EQUAL);
2225 // do global setup needed for the chosen lighting mode
2226 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2227 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2228 r_shadow_usingshadowmap2d = shadowmapping;
2229 r_shadow_rendermode = r_shadow_lightingrendermode;
2230 // only draw light where this geometry was already rendered AND the
2231 // stencil is 128 (values other than this mean shadow)
2233 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2235 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2238 static const unsigned short bboxelements[36] =
2248 static const float bboxpoints[8][3] =
2260 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2263 float vertex3f[8*3];
2264 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2265 // do global setup needed for the chosen lighting mode
2266 R_Shadow_RenderMode_Reset();
2267 r_shadow_rendermode = r_shadow_lightingrendermode;
2268 R_EntityMatrix(&identitymatrix);
2269 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2270 // only draw light where this geometry was already rendered AND the
2271 // stencil is 128 (values other than this mean shadow)
2272 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2273 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2275 r_shadow_usingshadowmap2d = shadowmapping;
2277 // render the lighting
2278 R_SetupShader_DeferredLight(rsurface.rtlight);
2279 for (i = 0;i < 8;i++)
2280 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2281 GL_ColorMask(1,1,1,1);
2282 GL_DepthMask(false);
2283 GL_DepthRange(0, 1);
2284 GL_PolygonOffset(0, 0);
2286 GL_DepthFunc(GL_GREATER);
2287 GL_CullFace(r_refdef.view.cullface_back);
2288 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL);
2289 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2292 static void R_Shadow_UpdateBounceGridTexture(void)
2294 #define MAXBOUNCEGRIDPARTICLESPERLIGHT 1048576
2296 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2300 int hitsupercontentsmask;
2308 unsigned char *pixel;
2309 unsigned char *pixels;
2310 unsigned int lightindex;
2312 unsigned int range1;
2313 unsigned int range2;
2314 unsigned int seed = (unsigned int)(realtime * 1000.0f);
2316 vec3_t baseshotcolor;
2328 vec_t lightintensity;
2330 qboolean isstatic = r_shadow_bouncegrid_updateinterval.value > 1.0f;
2332 if (!r_shadow_bouncegrid.integer || !vid.support.ext_texture_3d)
2334 if (r_shadow_bouncegridtexture)
2336 R_FreeTexture(r_shadow_bouncegridtexture);
2337 r_shadow_bouncegridtexture = NULL;
2341 if (r_refdef.scene.worldmodel && isstatic)
2343 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));
2344 VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
2345 VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
2346 VectorSubtract(maxs, mins, size);
2347 resolution[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2348 resolution[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2349 resolution[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2350 resolution[0] = min(resolution[0], bound(4, r_shadow_bouncegrid_x.integer, (int)vid.maxtexturesize_3d));
2351 resolution[1] = min(resolution[1], bound(4, r_shadow_bouncegrid_y.integer, (int)vid.maxtexturesize_3d));
2352 resolution[2] = min(resolution[2], bound(4, r_shadow_bouncegrid_z.integer, (int)vid.maxtexturesize_3d));
2353 spacing[0] = size[0] / resolution[0];
2354 spacing[1] = size[1] / resolution[1];
2355 spacing[2] = size[2] / resolution[2];
2356 ispacing[0] = 1.0f / spacing[0];
2357 ispacing[1] = 1.0f / spacing[1];
2358 ispacing[2] = 1.0f / spacing[2];
2362 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));
2363 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));
2364 VectorMultiply(resolution, spacing, size);
2365 ispacing[0] = 1.0f / spacing[0];
2366 ispacing[1] = 1.0f / spacing[1];
2367 ispacing[2] = 1.0f / spacing[2];
2368 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2369 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2370 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2371 VectorAdd(mins, size, maxs);
2373 memset(m, 0, sizeof(m));
2374 m[0] = 1.0f / size[0];
2375 m[3] = -mins[0] * m[0];
2376 m[5] = 1.0f / size[1];
2377 m[7] = -mins[1] * m[5];
2378 m[10] = 1.0f / size[2];
2379 m[11] = -mins[2] * m[10];
2381 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegridmatrix, m);
2382 r_shadow_bouncegridintensity = r_shadow_bouncegrid_intensity.value;
2383 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])
2385 numpixels = resolution[0]*resolution[1]*resolution[2];
2386 // allocate pixels for this update...
2387 pixels = Mem_Alloc(r_main_mempool, numpixels * sizeof(unsigned char[4]));
2388 // figure out what we want to interact with
2389 if (r_shadow_bouncegrid_hitmodels.integer)
2390 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK;
2392 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
2393 // iterate world rtlights
2394 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2395 range1 = isstatic ? 0 : r_refdef.scene.numlights;
2396 range2 = range + range1;
2397 for (lightindex = 0;lightindex < range2;lightindex++)
2401 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2402 if (!light || !(light->flags & flag))
2404 rtlight = &light->rtlight;
2405 // when static, we skip styled lights because they tend to change...
2406 if (rtlight->style > 0)
2408 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) * (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1), lightcolor);
2412 if (lightindex < range)
2414 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2415 rtlight = &light->rtlight;
2418 rtlight = r_refdef.scene.lights[lightindex - range];
2419 // draw only visible lights (major speedup)
2422 VectorScale(rtlight->currentcolor, rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale, lightcolor);
2424 if (!VectorLength2(lightcolor))
2426 // shoot particles from this light
2427 // use a calculation for the number of particles that will not
2428 // vary with lightstyle, otherwise we get randomized particle
2429 // distribution, the seeded random is only consistent for a
2430 // consistent number of particles on this light...
2431 radius = rtlight->radius * bound(0.0001f, r_shadow_bouncegrid_lightradiusscale.value, 1024.0f);
2432 s = rtlight->radius / bound(1.0f, r_shadow_bouncegrid_particlespacing.value, 1048576.0f);
2433 lightintensity = VectorLength(rtlight->color) * rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale;
2434 if (lightindex >= range)
2435 lightintensity *= r_shadow_bouncegrid_dlightparticlemultiplier.value;
2436 shootparticles = (int)bound(0, lightintensity * s *s, MAXBOUNCEGRIDPARTICLESPERLIGHT);
2437 if (!shootparticles)
2439 s = 255.0f * r_shadow_bouncegrid_particleintensity.value / shootparticles;
2440 VectorScale(lightcolor, s, baseshotcolor);
2441 maxbounce = bound(1, r_shadow_bouncegrid_maxbounce.integer, 16);
2442 if (VectorLength2(baseshotcolor) < 3.0f)
2444 r_refdef.stats.bouncegrid_lights++;
2445 r_refdef.stats.bouncegrid_particles += shootparticles;
2446 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2448 if (r_shadow_bouncegrid_stablerandom.integer > 0)
2449 seed = lightindex * 11937 + shotparticles;
2450 VectorCopy(baseshotcolor, shotcolor);
2451 VectorCopy(rtlight->shadoworigin, clipstart);
2452 if (r_shadow_bouncegrid_stablerandom.integer < 0)
2453 VectorRandom(clipend);
2455 VectorCheeseRandom(clipend);
2456 VectorMA(clipstart, radius, clipend, clipend);
2457 bouncelimit = 1 + (rtlight->particlecache_updateparticle % maxbounce);
2458 for (bouncecount = 0;;bouncecount++)
2460 r_refdef.stats.bouncegrid_traces++;
2461 cliptrace = CL_TraceLine(clipstart, clipend, r_shadow_bouncegrid_hitmodels.integer ? MOVE_HITMODEL : MOVE_NOMONSTERS, NULL, hitsupercontentsmask, true, false, NULL, true);
2462 //Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask);
2463 if (cliptrace.fraction >= 1.0f)
2465 r_refdef.stats.bouncegrid_hits++;
2466 if (bouncecount > 0)
2468 r_refdef.stats.bouncegrid_splats++;
2469 // figure out which texture pixel this is in
2470 tex[0] = (int)((cliptrace.endpos[0] - mins[0]) * ispacing[0]);
2471 tex[1] = (int)((cliptrace.endpos[1] - mins[1]) * ispacing[1]);
2472 tex[2] = (int)((cliptrace.endpos[2] - mins[2]) * ispacing[2]);
2473 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)
2475 // it is within bounds...
2476 pixel = pixels + 4 * ((tex[2]*resolution[1]+tex[1])*resolution[0]+tex[0]);
2477 // add to the pixel color
2478 c[0] = pixel[0] + (int)shotcolor[2];
2479 c[1] = pixel[1] + (int)shotcolor[1];
2480 c[2] = pixel[2] + (int)shotcolor[0];
2481 pixel[0] = (unsigned char)min(c[0], 255);
2482 pixel[1] = (unsigned char)min(c[1], 255);
2483 pixel[2] = (unsigned char)min(c[2], 255);
2487 if (bouncecount >= bouncelimit)
2489 // scale down shot color by bounce intensity and texture color
2490 VectorScale(shotcolor, r_shadow_bouncegrid_particlebounceintensity.value, shotcolor);
2491 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2492 VectorMultiply(shotcolor, rsurface.texture->currentskinframe->avgcolor, shotcolor);
2493 if (VectorLength2(shotcolor) < 3.0f)
2495 r_refdef.stats.bouncegrid_bounces++;
2496 if (r_shadow_bouncegrid_bounceanglediffuse.integer)
2498 // random direction, primarily along plane normal
2499 s = VectorDistance(cliptrace.endpos, clipend);
2500 if (r_shadow_bouncegrid_stablerandom.integer < 0)
2501 VectorRandom(clipend);
2503 VectorCheeseRandom(clipend);
2504 VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
2505 VectorNormalize(clipend);
2506 VectorScale(clipend, s, clipend);
2510 // reflect the remaining portion of the line across plane normal
2511 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2512 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2514 // calculate the new line start and end
2515 VectorCopy(cliptrace.endpos, clipstart);
2516 VectorAdd(clipstart, clipend, clipend);
2520 if (r_shadow_bouncegridtexture && r_shadow_bouncegridresolution[0] == resolution[0] && r_shadow_bouncegridresolution[1] == resolution[1] && r_shadow_bouncegridresolution[2] == resolution[2])
2521 R_UpdateTexture(r_shadow_bouncegridtexture, pixels, 0, 0, 0, resolution[0], resolution[1], resolution[2]);
2524 VectorCopy(resolution, r_shadow_bouncegridresolution);
2525 if (r_shadow_bouncegridtexture)
2526 R_FreeTexture(r_shadow_bouncegridtexture);
2527 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);
2530 r_shadow_bouncegridtime = realtime;
2533 #define MAXPARTICLESPERLIGHT 262144
2534 #define MAXLIGHTSPERDRAW 1024
2536 static void R_Shadow_RenderParticlesForLight(rtlight_t *rtlight)
2542 int hitsupercontentsmask;
2545 int shootparticles = 0;
2548 unsigned int seed = 0;
2549 static unsigned short bouncelight_elements[MAXLIGHTSPERDRAW*36];
2550 static float vertex3f[MAXLIGHTSPERDRAW*24];
2551 static float lightorigin4f[MAXLIGHTSPERDRAW*32];
2552 static float color4f[MAXLIGHTSPERDRAW*32];
2553 float scaledpoints[8][3];
2557 rtlight_particle_t *p;
2558 vec_t wantparticles = 0;
2562 vec_t iparticlesize;
2568 vec3_t currentcolor;
2573 if (!rtlight->draw || !rtlight->isstatic || !r_shadow_usingdeferredprepass)
2575 if (r_shadow_particletrace.integer)
2577 radius = rtlight->radius * bound(0.0001f, r_shadow_particletrace_radiusscale.value, 1.0f) - r_shadow_particletrace_size.value;
2578 s = rtlight->radius / bound(1.0f, r_shadow_particletrace_particlespacing.value * r_shadow_particletrace_size.value, 1048576.0f);
2579 wantparticles = s*s;
2580 n = (int)bound(0, wantparticles, MAXPARTICLESPERLIGHT);
2584 shootparticles = (int)(n * r_shadow_particletrace_updatepercentage.value);
2585 if ((n && !rtlight->particlecache_particles) || rtlight->particlecache_maxparticles != n)
2587 if (rtlight->particlecache_particles)
2588 Mem_Free(rtlight->particlecache_particles);
2589 rtlight->particlecache_particles = NULL;
2590 rtlight->particlecache_numparticles = 0;
2591 rtlight->particlecache_maxparticles = n;
2592 rtlight->particlecache_updateparticle = 0;
2593 if (rtlight->particlecache_maxparticles)
2594 rtlight->particlecache_particles = Mem_Alloc(r_main_mempool, rtlight->particlecache_maxparticles * sizeof(*rtlight->particlecache_particles));
2595 shootparticles = n * 16;
2598 if (!rtlight->particlecache_maxparticles)
2601 // if (rtlight->particlecache_numparticles < rtlight->particlecache_maxparticles)
2602 // shootparticles = rtlight->particlecache_maxparticles;
2604 // if (rtlight->particlecache_numparticles >= rtlight->particlecache_maxparticles)
2605 // shootparticles = 0;
2607 maxbounce = bound(1, r_shadow_particletrace_maxbounce.integer, 16);
2608 //r_refdef.stats.lights_bouncelightsupdated += shootparticles;
2609 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2611 seed = rtlight->particlecache_updateparticle;
2612 VectorSet(shotcolor, 1.0f, 1.0f, 1.0f);
2613 VectorCopy(rtlight->shadoworigin, clipstart);
2614 VectorRandom(clipend);
2615 VectorMA(clipstart, radius, clipend, clipend);
2616 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
2617 bouncelimit = 1 + (rtlight->particlecache_updateparticle % maxbounce);
2618 for (bouncecount = 0;;bouncecount++)
2620 cliptrace = CL_TraceLine(clipstart, clipend, MOVE_NOMONSTERS, NULL, hitsupercontentsmask, true, false, NULL, true);
2621 //Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask);
2622 if (cliptrace.fraction >= 1.0f)
2624 if (VectorLength2(shotcolor) < (1.0f / 262144.0f))
2626 if (bouncecount >= bouncelimit)
2628 VectorCopy(cliptrace.endpos, rtlight->particlecache_particles[rtlight->particlecache_updateparticle].origin);
2629 VectorCopy(shotcolor, rtlight->particlecache_particles[rtlight->particlecache_updateparticle].color);
2630 rtlight->particlecache_updateparticle++;
2631 if (rtlight->particlecache_numparticles < rtlight->particlecache_updateparticle)
2632 rtlight->particlecache_numparticles = rtlight->particlecache_updateparticle;
2633 if (rtlight->particlecache_updateparticle >= rtlight->particlecache_maxparticles)
2635 rtlight->particlecache_updateparticle = 0;
2636 shotparticles = shootparticles;
2640 // scale down shot color by bounce intensity and texture color
2641 VectorScale(shotcolor, r_shadow_particletrace_bounceintensity.value, shotcolor);
2642 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2643 VectorMultiply(shotcolor, rsurface.texture->currentskinframe->avgcolor, shotcolor);
2644 // reflect the remaining portion of the line across plane normal
2645 //VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2646 //VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2647 // random direction, primarily along plane normal
2648 s = VectorDistance(cliptrace.endpos, clipend);
2649 VectorRandom(clipend);
2650 VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
2651 VectorNormalize(clipend);
2652 VectorScale(clipend, s, clipend);
2653 // calculate the new line start and end
2654 VectorCopy(cliptrace.endpos, clipstart);
2655 VectorAdd(clipstart, clipend, clipend);
2659 if (!rtlight->particlecache_numparticles)
2662 // render the particles as deferred lights
2663 // do global setup needed for the chosen lighting mode
2664 R_Shadow_RenderMode_Reset();
2665 r_shadow_rendermode = r_shadow_lightingrendermode;
2666 r_shadow_usingshadowmap2d = false;
2667 R_EntityMatrix(&identitymatrix);
2668 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2669 // only draw light where this geometry was already rendered AND the
2670 // stencil is 128 (values other than this mean shadow)
2671 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2672 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
2673 R_SetupShader_DeferredBounceLight();
2674 GL_ColorMask(1,1,1,1);
2675 GL_DepthMask(false);
2676 GL_DepthRange(0, 1);
2677 GL_PolygonOffset(0, 0);
2679 GL_DepthFunc(GL_GREATER);
2680 GL_CullFace(r_refdef.view.cullface_back);
2681 s = r_shadow_particletrace_intensity.value / (float)rtlight->particlecache_numparticles;
2682 VectorScale(rtlight->currentcolor, s, currentcolor);
2683 particlesize = bound(0.0001f, r_shadow_particletrace_size.value, 1024.0f);
2684 iparticlesize = 1.0f / particlesize;
2685 // VectorScale(r_refdef.view.forward, particlesize, offset);
2686 // VectorScale(r_refdef.view.left, -particlesize, right);
2687 // VectorScale(r_refdef.view.up, particlesize, up);
2688 org[3] = iparticlesize;
2691 lo4f = lightorigin4f;
2694 if (!bouncelight_elements[1])
2695 for (i = 0;i < MAXLIGHTSPERDRAW;i++)
2696 for (j = 0;j < 36;j++)
2697 bouncelight_elements[i*36+j] = i*8+bboxelements[j];
2698 for (j = 0;j < 8;j++)
2699 VectorScale(bboxpoints[j], particlesize, scaledpoints[j]);
2700 //r_refdef.stats.lights_bouncelightscounted += rtlight->particlecache_numparticles;
2701 for (j = 0, p = rtlight->particlecache_particles, n = rtlight->particlecache_numparticles;j < n;j++, p++)
2703 VectorCopy(p->origin, org);
2704 // org[3] is set above
2705 VectorMultiply(p->color, currentcolor, color);
2706 // color[3] is set above
2707 VectorAdd(scaledpoints[0], org, v3f + 0);
2708 VectorAdd(scaledpoints[1], org, v3f + 3);
2709 VectorAdd(scaledpoints[2], org, v3f + 6);
2710 VectorAdd(scaledpoints[3], org, v3f + 9);
2711 VectorAdd(scaledpoints[4], org, v3f + 12);
2712 VectorAdd(scaledpoints[5], org, v3f + 15);
2713 VectorAdd(scaledpoints[6], org, v3f + 18);
2714 VectorAdd(scaledpoints[7], org, v3f + 21);
2715 Vector4Copy(org, lo4f + 0);
2716 Vector4Copy(org, lo4f + 4);
2717 Vector4Copy(org, lo4f + 8);
2718 Vector4Copy(org, lo4f + 12);
2719 Vector4Copy(org, lo4f + 16);
2720 Vector4Copy(org, lo4f + 20);
2721 Vector4Copy(org, lo4f + 24);
2722 Vector4Copy(org, lo4f + 28);
2723 Vector4Copy(color, c4f + 0);
2724 Vector4Copy(color, c4f + 4);
2725 Vector4Copy(color, c4f + 8);
2726 Vector4Copy(color, c4f + 12);
2727 Vector4Copy(color, c4f + 16);
2728 Vector4Copy(color, c4f + 20);
2729 Vector4Copy(color, c4f + 24);
2730 Vector4Copy(color, c4f + 28);
2735 if (batchcount >= MAXLIGHTSPERDRAW)
2737 //r_refdef.stats.lights_bouncelightsdrawn += batchcount;
2738 R_Mesh_PrepareVertices_BounceLight_Arrays(batchcount*8, vertex3f, color4f, lightorigin4f);
2739 R_Mesh_Draw(0, batchcount*8, 0, batchcount*12, NULL, NULL, 0, bouncelight_elements, NULL, 0);
2741 lo4f = lightorigin4f;
2748 //r_refdef.stats.lights_bouncelightsdrawn += batchcount;
2749 R_Mesh_PrepareVertices_BounceLight_Arrays(batchcount*8, vertex3f, color4f, lightorigin4f);
2750 R_Mesh_Draw(0, batchcount*8, 0, batchcount*12, NULL, NULL, 0, bouncelight_elements, NULL, 0);
2752 lo4f = lightorigin4f;
2758 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2760 R_Shadow_RenderMode_Reset();
2761 GL_BlendFunc(GL_ONE, GL_ONE);
2762 GL_DepthRange(0, 1);
2763 GL_DepthTest(r_showshadowvolumes.integer < 2);
2764 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2765 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2766 GL_CullFace(GL_NONE);
2767 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2770 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2772 R_Shadow_RenderMode_Reset();
2773 GL_BlendFunc(GL_ONE, GL_ONE);
2774 GL_DepthRange(0, 1);
2775 GL_DepthTest(r_showlighting.integer < 2);
2776 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2778 GL_DepthFunc(GL_EQUAL);
2779 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2780 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2783 void R_Shadow_RenderMode_End(void)
2785 R_Shadow_RenderMode_Reset();
2786 R_Shadow_RenderMode_ActiveLight(NULL);
2788 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2789 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2792 int bboxedges[12][2] =
2811 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2813 if (!r_shadow_scissor.integer)
2815 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2816 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2817 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2818 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2821 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2822 return true; // invisible
2823 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2824 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2825 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2826 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2827 r_refdef.stats.lights_scissored++;
2831 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2834 const float *vertex3f;
2835 const float *normal3f;
2837 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2838 switch (r_shadow_rendermode)
2840 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2841 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2842 if (VectorLength2(diffusecolor) > 0)
2844 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)
2846 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2847 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2848 if ((dot = DotProduct(n, v)) < 0)
2850 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2851 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2854 VectorCopy(ambientcolor, color4f);
2855 if (r_refdef.fogenabled)
2858 f = RSurf_FogVertex(vertex3f);
2859 VectorScale(color4f, f, color4f);
2866 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2868 VectorCopy(ambientcolor, color4f);
2869 if (r_refdef.fogenabled)
2872 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2873 f = RSurf_FogVertex(vertex3f);
2874 VectorScale(color4f + 4*i, f, color4f);
2880 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2881 if (VectorLength2(diffusecolor) > 0)
2883 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)
2885 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2886 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2888 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2889 if ((dot = DotProduct(n, v)) < 0)
2891 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2892 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2893 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2894 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2898 color4f[0] = ambientcolor[0] * distintensity;
2899 color4f[1] = ambientcolor[1] * distintensity;
2900 color4f[2] = ambientcolor[2] * distintensity;
2902 if (r_refdef.fogenabled)
2905 f = RSurf_FogVertex(vertex3f);
2906 VectorScale(color4f, f, color4f);
2910 VectorClear(color4f);
2916 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2918 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2919 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2921 color4f[0] = ambientcolor[0] * distintensity;
2922 color4f[1] = ambientcolor[1] * distintensity;
2923 color4f[2] = ambientcolor[2] * distintensity;
2924 if (r_refdef.fogenabled)
2927 f = RSurf_FogVertex(vertex3f);
2928 VectorScale(color4f, f, color4f);
2932 VectorClear(color4f);
2937 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2938 if (VectorLength2(diffusecolor) > 0)
2940 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)
2942 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2943 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2945 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2946 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2947 if ((dot = DotProduct(n, v)) < 0)
2949 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2950 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2951 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2952 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2956 color4f[0] = ambientcolor[0] * distintensity;
2957 color4f[1] = ambientcolor[1] * distintensity;
2958 color4f[2] = ambientcolor[2] * distintensity;
2960 if (r_refdef.fogenabled)
2963 f = RSurf_FogVertex(vertex3f);
2964 VectorScale(color4f, f, color4f);
2968 VectorClear(color4f);
2974 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2976 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2977 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2979 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2980 color4f[0] = ambientcolor[0] * distintensity;
2981 color4f[1] = ambientcolor[1] * distintensity;
2982 color4f[2] = ambientcolor[2] * distintensity;
2983 if (r_refdef.fogenabled)
2986 f = RSurf_FogVertex(vertex3f);
2987 VectorScale(color4f, f, color4f);
2991 VectorClear(color4f);
3001 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3003 // used to display how many times a surface is lit for level design purposes
3004 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3005 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3009 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
3011 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3012 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
3013 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
3014 GL_DepthFunc(GL_EQUAL);
3016 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
3017 GL_DepthFunc(GL_LEQUAL);
3020 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3027 int newnumtriangles;
3031 int maxtriangles = 4096;
3032 static int newelements[4096*3];
3033 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3034 for (renders = 0;renders < 4;renders++)
3039 newnumtriangles = 0;
3041 // due to low fillrate on the cards this vertex lighting path is
3042 // designed for, we manually cull all triangles that do not
3043 // contain a lit vertex
3044 // this builds batches of triangles from multiple surfaces and
3045 // renders them at once
3046 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3048 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3050 if (newnumtriangles)
3052 newfirstvertex = min(newfirstvertex, e[0]);
3053 newlastvertex = max(newlastvertex, e[0]);
3057 newfirstvertex = e[0];
3058 newlastvertex = e[0];
3060 newfirstvertex = min(newfirstvertex, e[1]);
3061 newlastvertex = max(newlastvertex, e[1]);
3062 newfirstvertex = min(newfirstvertex, e[2]);
3063 newlastvertex = max(newlastvertex, e[2]);
3069 if (newnumtriangles >= maxtriangles)
3071 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3072 newnumtriangles = 0;
3078 if (newnumtriangles >= 1)
3080 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3083 // if we couldn't find any lit triangles, exit early
3086 // now reduce the intensity for the next overbright pass
3087 // we have to clamp to 0 here incase the drivers have improper
3088 // handling of negative colors
3089 // (some old drivers even have improper handling of >1 color)
3091 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3093 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3095 c[0] = max(0, c[0] - 1);
3096 c[1] = max(0, c[1] - 1);
3097 c[2] = max(0, c[2] - 1);
3109 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
3111 // OpenGL 1.1 path (anything)
3112 float ambientcolorbase[3], diffusecolorbase[3];
3113 float ambientcolorpants[3], diffusecolorpants[3];
3114 float ambientcolorshirt[3], diffusecolorshirt[3];
3115 const float *surfacecolor = rsurface.texture->dlightcolor;
3116 const float *surfacepants = rsurface.colormap_pantscolor;
3117 const float *surfaceshirt = rsurface.colormap_shirtcolor;
3118 rtexture_t *basetexture = rsurface.texture->basetexture;
3119 rtexture_t *pantstexture = rsurface.texture->pantstexture;
3120 rtexture_t *shirttexture = rsurface.texture->shirttexture;
3121 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3122 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3123 ambientscale *= 2 * r_refdef.view.colorscale;
3124 diffusescale *= 2 * r_refdef.view.colorscale;
3125 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3126 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3127 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3128 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3129 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3130 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
3131 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3132 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
3133 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3134 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
3135 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
3136 R_Mesh_TexBind(0, basetexture);
3137 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
3138 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
3139 switch(r_shadow_rendermode)
3141 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3142 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
3143 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3144 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3145 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3147 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3148 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
3149 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
3150 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
3151 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3153 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3154 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
3155 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3156 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3157 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3159 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3164 //R_Mesh_TexBind(0, basetexture);
3165 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
3168 R_Mesh_TexBind(0, pantstexture);
3169 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
3173 R_Mesh_TexBind(0, shirttexture);
3174 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
3178 extern cvar_t gl_lightmaps;
3179 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3181 float ambientscale, diffusescale, specularscale;
3183 float lightcolor[3];
3184 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
3185 ambientscale = rsurface.rtlight->ambientscale;
3186 diffusescale = rsurface.rtlight->diffusescale;
3187 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3188 if (!r_shadow_usenormalmap.integer)
3190 ambientscale += 1.0f * diffusescale;
3194 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
3196 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
3199 VectorNegate(lightcolor, lightcolor);
3200 switch(vid.renderpath)
3202 case RENDERPATH_GL11:
3203 case RENDERPATH_GL13:
3204 case RENDERPATH_GL20:
3205 case RENDERPATH_GLES2:
3206 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
3208 case RENDERPATH_D3D9:
3210 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
3213 case RENDERPATH_D3D10:
3214 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3216 case RENDERPATH_D3D11:
3217 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3219 case RENDERPATH_SOFT:
3220 DPSOFTRAST_BlendSubtract(true);
3224 RSurf_SetupDepthAndCulling();
3225 switch (r_shadow_rendermode)
3227 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3228 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3229 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
3231 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3232 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
3234 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3235 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3236 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3237 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3238 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
3241 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3246 switch(vid.renderpath)
3248 case RENDERPATH_GL11:
3249 case RENDERPATH_GL13:
3250 case RENDERPATH_GL20:
3251 case RENDERPATH_GLES2:
3252 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
3254 case RENDERPATH_D3D9:
3256 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
3259 case RENDERPATH_D3D10:
3260 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3262 case RENDERPATH_D3D11:
3263 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3265 case RENDERPATH_SOFT:
3266 DPSOFTRAST_BlendSubtract(false);
3272 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)
3274 matrix4x4_t tempmatrix = *matrix;
3275 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3277 // if this light has been compiled before, free the associated data
3278 R_RTLight_Uncompile(rtlight);
3280 // clear it completely to avoid any lingering data
3281 memset(rtlight, 0, sizeof(*rtlight));
3283 // copy the properties
3284 rtlight->matrix_lighttoworld = tempmatrix;
3285 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3286 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3287 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3288 VectorCopy(color, rtlight->color);
3289 rtlight->cubemapname[0] = 0;
3290 if (cubemapname && cubemapname[0])
3291 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3292 rtlight->shadow = shadow;
3293 rtlight->corona = corona;
3294 rtlight->style = style;
3295 rtlight->isstatic = isstatic;
3296 rtlight->coronasizescale = coronasizescale;
3297 rtlight->ambientscale = ambientscale;
3298 rtlight->diffusescale = diffusescale;
3299 rtlight->specularscale = specularscale;
3300 rtlight->flags = flags;
3302 // compute derived data
3303 //rtlight->cullradius = rtlight->radius;
3304 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3305 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3306 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3307 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3308 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3309 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3310 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3313 // compiles rtlight geometry
3314 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3315 void R_RTLight_Compile(rtlight_t *rtlight)
3318 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3319 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3320 entity_render_t *ent = r_refdef.scene.worldentity;
3321 dp_model_t *model = r_refdef.scene.worldmodel;
3322 unsigned char *data;
3325 // compile the light
3326 rtlight->compiled = true;
3327 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3328 rtlight->static_numleafs = 0;
3329 rtlight->static_numleafpvsbytes = 0;
3330 rtlight->static_leaflist = NULL;
3331 rtlight->static_leafpvs = NULL;
3332 rtlight->static_numsurfaces = 0;
3333 rtlight->static_surfacelist = NULL;
3334 rtlight->static_shadowmap_receivers = 0x3F;
3335 rtlight->static_shadowmap_casters = 0x3F;
3336 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3337 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3338 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3339 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3340 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3341 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3343 if (model && model->GetLightInfo)
3345 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3346 r_shadow_compilingrtlight = rtlight;
3347 R_FrameData_SetMark();
3348 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);
3349 R_FrameData_ReturnToMark();
3350 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3351 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3352 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3353 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3354 rtlight->static_numsurfaces = numsurfaces;
3355 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3356 rtlight->static_numleafs = numleafs;
3357 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3358 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3359 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3360 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3361 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3362 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3363 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3364 if (rtlight->static_numsurfaces)
3365 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3366 if (rtlight->static_numleafs)
3367 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3368 if (rtlight->static_numleafpvsbytes)
3369 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3370 if (rtlight->static_numshadowtrispvsbytes)
3371 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3372 if (rtlight->static_numlighttrispvsbytes)
3373 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3374 R_FrameData_SetMark();
3375 switch (rtlight->shadowmode)
3377 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3378 if (model->CompileShadowMap && rtlight->shadow)
3379 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3382 if (model->CompileShadowVolume && rtlight->shadow)
3383 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3386 R_FrameData_ReturnToMark();
3387 // now we're done compiling the rtlight
3388 r_shadow_compilingrtlight = NULL;
3392 // use smallest available cullradius - box radius or light radius
3393 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3394 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3396 shadowzpasstris = 0;
3397 if (rtlight->static_meshchain_shadow_zpass)
3398 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3399 shadowzpasstris += mesh->numtriangles;
3401 shadowzfailtris = 0;
3402 if (rtlight->static_meshchain_shadow_zfail)
3403 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3404 shadowzfailtris += mesh->numtriangles;
3407 if (rtlight->static_numlighttrispvsbytes)
3408 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3409 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3413 if (rtlight->static_numlighttrispvsbytes)
3414 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3415 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3418 if (developer_extra.integer)
3419 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);
3422 void R_RTLight_Uncompile(rtlight_t *rtlight)
3424 if (rtlight->compiled)
3426 if (rtlight->static_meshchain_shadow_zpass)
3427 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3428 rtlight->static_meshchain_shadow_zpass = NULL;
3429 if (rtlight->static_meshchain_shadow_zfail)
3430 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3431 rtlight->static_meshchain_shadow_zfail = NULL;
3432 if (rtlight->static_meshchain_shadow_shadowmap)
3433 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3434 rtlight->static_meshchain_shadow_shadowmap = NULL;
3435 // these allocations are grouped
3436 if (rtlight->static_surfacelist)
3437 Mem_Free(rtlight->static_surfacelist);
3438 rtlight->static_numleafs = 0;
3439 rtlight->static_numleafpvsbytes = 0;
3440 rtlight->static_leaflist = NULL;
3441 rtlight->static_leafpvs = NULL;
3442 rtlight->static_numsurfaces = 0;
3443 rtlight->static_surfacelist = NULL;
3444 rtlight->static_numshadowtrispvsbytes = 0;
3445 rtlight->static_shadowtrispvs = NULL;
3446 rtlight->static_numlighttrispvsbytes = 0;
3447 rtlight->static_lighttrispvs = NULL;
3448 rtlight->compiled = false;
3452 void R_Shadow_UncompileWorldLights(void)
3456 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3457 for (lightindex = 0;lightindex < range;lightindex++)
3459 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3462 R_RTLight_Uncompile(&light->rtlight);
3466 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3470 // reset the count of frustum planes
3471 // see rtlight->cached_frustumplanes definition for how much this array
3473 rtlight->cached_numfrustumplanes = 0;
3475 // haven't implemented a culling path for ortho rendering
3476 if (!r_refdef.view.useperspective)
3478 // check if the light is on screen and copy the 4 planes if it is
3479 for (i = 0;i < 4;i++)
3480 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3483 for (i = 0;i < 4;i++)
3484 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3489 // generate a deformed frustum that includes the light origin, this is
3490 // used to cull shadow casting surfaces that can not possibly cast a
3491 // shadow onto the visible light-receiving surfaces, which can be a
3494 // if the light origin is onscreen the result will be 4 planes exactly
3495 // if the light origin is offscreen on only one axis the result will
3496 // be exactly 5 planes (split-side case)
3497 // if the light origin is offscreen on two axes the result will be
3498 // exactly 4 planes (stretched corner case)
3499 for (i = 0;i < 4;i++)
3501 // quickly reject standard frustum planes that put the light
3502 // origin outside the frustum
3503 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3506 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3508 // if all the standard frustum planes were accepted, the light is onscreen
3509 // otherwise we need to generate some more planes below...
3510 if (rtlight->cached_numfrustumplanes < 4)
3512 // at least one of the stock frustum planes failed, so we need to
3513 // create one or two custom planes to enclose the light origin
3514 for (i = 0;i < 4;i++)
3516 // create a plane using the view origin and light origin, and a
3517 // single point from the frustum corner set
3518 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3519 VectorNormalize(plane.normal);
3520 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3521 // see if this plane is backwards and flip it if so
3522 for (j = 0;j < 4;j++)
3523 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3527 VectorNegate(plane.normal, plane.normal);
3529 // flipped plane, test again to see if it is now valid
3530 for (j = 0;j < 4;j++)
3531 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3533 // if the plane is still not valid, then it is dividing the
3534 // frustum and has to be rejected
3538 // we have created a valid plane, compute extra info
3539 PlaneClassify(&plane);
3541 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3543 // if we've found 5 frustum planes then we have constructed a
3544 // proper split-side case and do not need to keep searching for
3545 // planes to enclose the light origin
3546 if (rtlight->cached_numfrustumplanes == 5)
3554 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3556 plane = rtlight->cached_frustumplanes[i];
3557 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));
3562 // now add the light-space box planes if the light box is rotated, as any
3563 // caster outside the oriented light box is irrelevant (even if it passed
3564 // the worldspace light box, which is axial)
3565 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3567 for (i = 0;i < 6;i++)
3571 v[i >> 1] = (i & 1) ? -1 : 1;
3572 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3573 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3574 plane.dist = VectorNormalizeLength(plane.normal);
3575 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3576 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3582 // add the world-space reduced box planes
3583 for (i = 0;i < 6;i++)
3585 VectorClear(plane.normal);
3586 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3587 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3588 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3597 // reduce all plane distances to tightly fit the rtlight cull box, which
3599 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3600 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3601 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3602 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3603 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3604 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3605 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3606 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3607 oldnum = rtlight->cached_numfrustumplanes;
3608 rtlight->cached_numfrustumplanes = 0;
3609 for (j = 0;j < oldnum;j++)
3611 // find the nearest point on the box to this plane
3612 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3613 for (i = 1;i < 8;i++)
3615 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3616 if (bestdist > dist)
3619 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);
3620 // if the nearest point is near or behind the plane, we want this
3621 // plane, otherwise the plane is useless as it won't cull anything
3622 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3624 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3625 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3632 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3636 RSurf_ActiveWorldEntity();
3638 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3641 GL_CullFace(GL_NONE);
3642 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3643 for (;mesh;mesh = mesh->next)
3645 if (!mesh->sidetotals[r_shadow_shadowmapside])
3647 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3648 if (mesh->vertex3fbuffer)
3649 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3651 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3652 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);
3656 else if (r_refdef.scene.worldentity->model)
3657 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);
3659 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3662 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3664 qboolean zpass = false;
3667 int surfacelistindex;
3668 msurface_t *surface;
3670 // if triangle neighbors are disabled, shadowvolumes are disabled
3671 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
3674 RSurf_ActiveWorldEntity();
3676 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3679 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3681 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3682 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3684 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3685 for (;mesh;mesh = mesh->next)
3687 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3688 if (mesh->vertex3fbuffer)
3689 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3691 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3692 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3694 // increment stencil if frontface is infront of depthbuffer
3695 GL_CullFace(r_refdef.view.cullface_back);
3696 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3697 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);
3698 // decrement stencil if backface is infront of depthbuffer
3699 GL_CullFace(r_refdef.view.cullface_front);
3700 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3702 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3704 // decrement stencil if backface is behind depthbuffer
3705 GL_CullFace(r_refdef.view.cullface_front);
3706 R_SetStencil(true, 255, GL_KEEP, GL_DECR, 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);
3708 // increment stencil if frontface is behind depthbuffer
3709 GL_CullFace(r_refdef.view.cullface_back);
3710 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3712 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);
3716 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3718 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3719 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3720 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3722 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3723 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3724 if (CHECKPVSBIT(trispvs, t))
3725 shadowmarklist[numshadowmark++] = t;
3727 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);
3729 else if (numsurfaces)
3731 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);
3734 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3737 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3739 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3740 vec_t relativeshadowradius;
3741 RSurf_ActiveModelEntity(ent, false, false, false);
3742 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3743 // we need to re-init the shader for each entity because the matrix changed
3744 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3745 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3746 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3747 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3748 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3749 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3750 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3751 switch (r_shadow_rendermode)
3753 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3754 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3757 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3760 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3763 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3765 // set up properties for rendering light onto this entity
3766 RSurf_ActiveModelEntity(ent, true, true, false);
3767 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3768 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3769 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3770 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3773 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3775 if (!r_refdef.scene.worldmodel->DrawLight)
3778 // set up properties for rendering light onto this entity
3779 RSurf_ActiveWorldEntity();
3780 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3781 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3782 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3783 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3785 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3787 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3790 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3792 dp_model_t *model = ent->model;
3793 if (!model->DrawLight)
3796 R_Shadow_SetupEntityLight(ent);
3798 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3800 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3803 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3807 int numleafs, numsurfaces;
3808 int *leaflist, *surfacelist;
3809 unsigned char *leafpvs;
3810 unsigned char *shadowtrispvs;
3811 unsigned char *lighttrispvs;
3812 //unsigned char *surfacesides;
3813 int numlightentities;
3814 int numlightentities_noselfshadow;
3815 int numshadowentities;
3816 int numshadowentities_noselfshadow;
3817 static entity_render_t *lightentities[MAX_EDICTS];
3818 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3819 static entity_render_t *shadowentities[MAX_EDICTS];
3820 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3823 rtlight->draw = false;
3825 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3826 // skip lights that are basically invisible (color 0 0 0)
3827 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3829 // loading is done before visibility checks because loading should happen
3830 // all at once at the start of a level, not when it stalls gameplay.
3831 // (especially important to benchmarks)
3833 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3835 if (rtlight->compiled)
3836 R_RTLight_Uncompile(rtlight);
3837 R_RTLight_Compile(rtlight);
3841 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3843 // look up the light style value at this time
3844 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3845 VectorScale(rtlight->color, f, rtlight->currentcolor);
3847 if (rtlight->selected)
3849 f = 2 + sin(realtime * M_PI * 4.0);
3850 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3854 // if lightstyle is currently off, don't draw the light
3855 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3858 // skip processing on corona-only lights
3862 // if the light box is offscreen, skip it
3863 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3866 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3867 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3869 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3871 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3873 // compiled light, world available and can receive realtime lighting
3874 // retrieve leaf information
3875 numleafs = rtlight->static_numleafs;
3876 leaflist = rtlight->static_leaflist;
3877 leafpvs = rtlight->static_leafpvs;
3878 numsurfaces = rtlight->static_numsurfaces;
3879 surfacelist = rtlight->static_surfacelist;
3880 //surfacesides = NULL;
3881 shadowtrispvs = rtlight->static_shadowtrispvs;
3882 lighttrispvs = rtlight->static_lighttrispvs;
3884 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3886 // dynamic light, world available and can receive realtime lighting
3887 // calculate lit surfaces and leafs
3888 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);
3889 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3890 leaflist = r_shadow_buffer_leaflist;
3891 leafpvs = r_shadow_buffer_leafpvs;
3892 surfacelist = r_shadow_buffer_surfacelist;
3893 //surfacesides = r_shadow_buffer_surfacesides;
3894 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3895 lighttrispvs = r_shadow_buffer_lighttrispvs;
3896 // if the reduced leaf bounds are offscreen, skip it
3897 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3908 //surfacesides = NULL;
3909 shadowtrispvs = NULL;
3910 lighttrispvs = NULL;
3912 // check if light is illuminating any visible leafs
3915 for (i = 0;i < numleafs;i++)
3916 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3922 // make a list of lit entities and shadow casting entities
3923 numlightentities = 0;
3924 numlightentities_noselfshadow = 0;
3925 numshadowentities = 0;
3926 numshadowentities_noselfshadow = 0;
3928 // add dynamic entities that are lit by the light
3929 for (i = 0;i < r_refdef.scene.numentities;i++)
3932 entity_render_t *ent = r_refdef.scene.entities[i];
3934 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3936 // skip the object entirely if it is not within the valid
3937 // shadow-casting region (which includes the lit region)
3938 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3940 if (!(model = ent->model))
3942 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3944 // this entity wants to receive light, is visible, and is
3945 // inside the light box
3946 // TODO: check if the surfaces in the model can receive light
3947 // so now check if it's in a leaf seen by the light
3948 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))
3950 if (ent->flags & RENDER_NOSELFSHADOW)
3951 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3953 lightentities[numlightentities++] = ent;
3954 // since it is lit, it probably also casts a shadow...
3955 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3956 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3957 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3959 // note: exterior models without the RENDER_NOSELFSHADOW
3960 // flag still create a RENDER_NOSELFSHADOW shadow but
3961 // are lit normally, this means that they are
3962 // self-shadowing but do not shadow other
3963 // RENDER_NOSELFSHADOW entities such as the gun
3964 // (very weird, but keeps the player shadow off the gun)
3965 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3966 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3968 shadowentities[numshadowentities++] = ent;
3971 else if (ent->flags & RENDER_SHADOW)
3973 // this entity is not receiving light, but may still need to
3975 // TODO: check if the surfaces in the model can cast shadow
3976 // now check if it is in a leaf seen by the light
3977 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))
3979 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3980 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3981 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3983 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3984 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3986 shadowentities[numshadowentities++] = ent;
3991 // return if there's nothing at all to light
3992 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3995 // count this light in the r_speeds
3996 r_refdef.stats.lights++;
3998 // flag it as worth drawing later
3999 rtlight->draw = true;
4001 // cache all the animated entities that cast a shadow but are not visible
4002 for (i = 0;i < numshadowentities;i++)
4003 if (!shadowentities[i]->animcache_vertex3f)
4004 R_AnimCache_GetEntity(shadowentities[i], false, false);
4005 for (i = 0;i < numshadowentities_noselfshadow;i++)
4006 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
4007 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4009 // allocate some temporary memory for rendering this light later in the frame
4010 // reusable buffers need to be copied, static data can be used as-is
4011 rtlight->cached_numlightentities = numlightentities;
4012 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
4013 rtlight->cached_numshadowentities = numshadowentities;
4014 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4015 rtlight->cached_numsurfaces = numsurfaces;
4016 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4017 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4018 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4019 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4020 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4022 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4023 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4024 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4025 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4026 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4030 // compiled light data
4031 rtlight->cached_shadowtrispvs = shadowtrispvs;
4032 rtlight->cached_lighttrispvs = lighttrispvs;
4033 rtlight->cached_surfacelist = surfacelist;
4037 void R_Shadow_DrawLight(rtlight_t *rtlight)
4041 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4042 int numlightentities;
4043 int numlightentities_noselfshadow;
4044 int numshadowentities;
4045 int numshadowentities_noselfshadow;
4046 entity_render_t **lightentities;
4047 entity_render_t **lightentities_noselfshadow;
4048 entity_render_t **shadowentities;
4049 entity_render_t **shadowentities_noselfshadow;
4051 static unsigned char entitysides[MAX_EDICTS];
4052 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4053 vec3_t nearestpoint;
4055 qboolean castshadows;
4058 // check if we cached this light this frame (meaning it is worth drawing)
4062 numlightentities = rtlight->cached_numlightentities;
4063 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4064 numshadowentities = rtlight->cached_numshadowentities;
4065 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4066 numsurfaces = rtlight->cached_numsurfaces;
4067 lightentities = rtlight->cached_lightentities;
4068 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4069 shadowentities = rtlight->cached_shadowentities;
4070 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4071 shadowtrispvs = rtlight->cached_shadowtrispvs;
4072 lighttrispvs = rtlight->cached_lighttrispvs;
4073 surfacelist = rtlight->cached_surfacelist;
4075 // set up a scissor rectangle for this light
4076 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4079 // don't let sound skip if going slow
4080 if (r_refdef.scene.extraupdate)
4083 // make this the active rtlight for rendering purposes
4084 R_Shadow_RenderMode_ActiveLight(rtlight);
4086 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4088 // optionally draw visible shape of the shadow volumes
4089 // for performance analysis by level designers
4090 R_Shadow_RenderMode_VisibleShadowVolumes();
4092 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4093 for (i = 0;i < numshadowentities;i++)
4094 R_Shadow_DrawEntityShadow(shadowentities[i]);
4095 for (i = 0;i < numshadowentities_noselfshadow;i++)
4096 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4097 R_Shadow_RenderMode_VisibleLighting(false, false);
4100 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4102 // optionally draw the illuminated areas
4103 // for performance analysis by level designers
4104 R_Shadow_RenderMode_VisibleLighting(false, false);
4106 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4107 for (i = 0;i < numlightentities;i++)
4108 R_Shadow_DrawEntityLight(lightentities[i]);
4109 for (i = 0;i < numlightentities_noselfshadow;i++)
4110 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4113 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4115 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4116 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4117 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4118 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4120 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
4121 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4122 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4124 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4130 int receivermask = 0;
4131 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4132 Matrix4x4_Abs(&radiustolight);
4134 r_shadow_shadowmaplod = 0;
4135 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4136 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
4137 r_shadow_shadowmaplod = i;
4139 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4141 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4143 surfacesides = NULL;
4146 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4148 castermask = rtlight->static_shadowmap_casters;
4149 receivermask = rtlight->static_shadowmap_receivers;
4153 surfacesides = r_shadow_buffer_surfacesides;
4154 for(i = 0;i < numsurfaces;i++)
4156 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4157 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4158 castermask |= surfacesides[i];
4159 receivermask |= surfacesides[i];
4163 if (receivermask < 0x3F)
4165 for (i = 0;i < numlightentities;i++)
4166 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4167 if (receivermask < 0x3F)
4168 for(i = 0; i < numlightentities_noselfshadow;i++)
4169 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4172 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4176 for (i = 0;i < numshadowentities;i++)
4177 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4178 for (i = 0;i < numshadowentities_noselfshadow;i++)
4179 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4182 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4184 // render shadow casters into 6 sided depth texture
4185 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4187 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
4188 if (! (castermask & (1 << side))) continue;
4190 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4191 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4192 R_Shadow_DrawEntityShadow(shadowentities[i]);
4195 if (numlightentities_noselfshadow)
4197 // render lighting using the depth texture as shadowmap
4198 // draw lighting in the unmasked areas
4199 R_Shadow_RenderMode_Lighting(false, false, true);
4200 for (i = 0;i < numlightentities_noselfshadow;i++)
4201 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4204 // render shadow casters into 6 sided depth texture
4205 if (numshadowentities_noselfshadow)
4207 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4209 R_Shadow_RenderMode_ShadowMap(side, 0, size);
4210 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
4211 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4215 // render lighting using the depth texture as shadowmap
4216 // draw lighting in the unmasked areas
4217 R_Shadow_RenderMode_Lighting(false, false, true);
4218 // draw lighting in the unmasked areas
4220 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4221 for (i = 0;i < numlightentities;i++)
4222 R_Shadow_DrawEntityLight(lightentities[i]);
4224 else if (castshadows && vid.stencil)
4226 // draw stencil shadow volumes to mask off pixels that are in shadow
4227 // so that they won't receive lighting
4228 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4229 R_Shadow_ClearStencil();
4232 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4233 for (i = 0;i < numshadowentities;i++)
4234 R_Shadow_DrawEntityShadow(shadowentities[i]);
4236 // draw lighting in the unmasked areas
4237 R_Shadow_RenderMode_Lighting(true, false, false);
4238 for (i = 0;i < numlightentities_noselfshadow;i++)
4239 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4241 for (i = 0;i < numshadowentities_noselfshadow;i++)
4242 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4244 // draw lighting in the unmasked areas
4245 R_Shadow_RenderMode_Lighting(true, false, false);
4247 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4248 for (i = 0;i < numlightentities;i++)
4249 R_Shadow_DrawEntityLight(lightentities[i]);
4253 // draw lighting in the unmasked areas
4254 R_Shadow_RenderMode_Lighting(false, false, false);
4256 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4257 for (i = 0;i < numlightentities;i++)
4258 R_Shadow_DrawEntityLight(lightentities[i]);
4259 for (i = 0;i < numlightentities_noselfshadow;i++)
4260 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4263 if (r_shadow_usingdeferredprepass)
4265 // when rendering deferred lighting, we simply rasterize the box
4266 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4267 R_Shadow_RenderMode_DrawDeferredLight(false, true);
4268 else if (castshadows && vid.stencil)
4269 R_Shadow_RenderMode_DrawDeferredLight(true, false);
4271 R_Shadow_RenderMode_DrawDeferredLight(false, false);
4274 if (r_shadow_particletrace.integer)
4275 R_Shadow_RenderParticlesForLight(rtlight);
4278 static void R_Shadow_FreeDeferred(void)
4280 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
4281 r_shadow_prepassgeometryfbo = 0;
4283 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
4284 r_shadow_prepasslightingdiffusespecularfbo = 0;
4286 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
4287 r_shadow_prepasslightingdiffusefbo = 0;
4289 if (r_shadow_prepassgeometrydepthtexture)
4290 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
4291 r_shadow_prepassgeometrydepthtexture = NULL;
4293 if (r_shadow_prepassgeometrydepthcolortexture)
4294 R_FreeTexture(r_shadow_prepassgeometrydepthcolortexture);
4295 r_shadow_prepassgeometrydepthcolortexture = NULL;
4297 if (r_shadow_prepassgeometrynormalmaptexture)
4298 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4299 r_shadow_prepassgeometrynormalmaptexture = NULL;
4301 if (r_shadow_prepasslightingdiffusetexture)
4302 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
4303 r_shadow_prepasslightingdiffusetexture = NULL;
4305 if (r_shadow_prepasslightingspeculartexture)
4306 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4307 r_shadow_prepasslightingspeculartexture = NULL;
4310 void R_Shadow_DrawPrepass(void)
4318 entity_render_t *ent;
4319 float clearcolor[4];
4321 R_Mesh_ResetTextureState();
4323 GL_ColorMask(1,1,1,1);
4324 GL_BlendFunc(GL_ONE, GL_ZERO);
4327 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4328 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4329 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4330 if (r_timereport_active)
4331 R_TimeReport("prepasscleargeom");
4333 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4334 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4335 if (r_timereport_active)
4336 R_TimeReport("prepassworld");
4338 for (i = 0;i < r_refdef.scene.numentities;i++)
4340 if (!r_refdef.viewcache.entityvisible[i])
4342 ent = r_refdef.scene.entities[i];
4343 if (ent->model && ent->model->DrawPrepass != NULL)
4344 ent->model->DrawPrepass(ent);
4347 if (r_timereport_active)
4348 R_TimeReport("prepassmodels");
4350 GL_DepthMask(false);
4351 GL_ColorMask(1,1,1,1);
4354 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4355 Vector4Set(clearcolor, 0, 0, 0, 0);
4356 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4357 if (r_timereport_active)
4358 R_TimeReport("prepassclearlit");
4360 R_Shadow_RenderMode_Begin();
4362 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4363 if (r_shadow_debuglight.integer >= 0)
4365 lightindex = r_shadow_debuglight.integer;
4366 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4367 if (light && (light->flags & flag) && light->rtlight.draw)
4368 R_Shadow_DrawLight(&light->rtlight);
4372 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4373 for (lightindex = 0;lightindex < range;lightindex++)
4375 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4376 if (light && (light->flags & flag) && light->rtlight.draw)
4377 R_Shadow_DrawLight(&light->rtlight);
4380 if (r_refdef.scene.rtdlight)
4381 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4382 if (r_refdef.scene.lights[lnum]->draw)
4383 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4385 R_Mesh_ResetRenderTargets();
4387 R_Shadow_RenderMode_End();
4389 if (r_timereport_active)
4390 R_TimeReport("prepasslights");
4393 void R_Shadow_DrawLightSprites(void);
4394 void R_Shadow_PrepareLights(void)
4404 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4405 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4406 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
4407 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4408 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4409 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4410 R_Shadow_FreeShadowMaps();
4412 r_shadow_usingshadowmaportho = false;
4414 switch (vid.renderpath)
4416 case RENDERPATH_GL20:
4417 case RENDERPATH_D3D9:
4418 case RENDERPATH_D3D10:
4419 case RENDERPATH_D3D11:
4420 case RENDERPATH_SOFT:
4421 case RENDERPATH_GLES2:
4422 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4424 r_shadow_usingdeferredprepass = false;
4425 if (r_shadow_prepass_width)
4426 R_Shadow_FreeDeferred();
4427 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4431 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4433 R_Shadow_FreeDeferred();
4435 r_shadow_usingdeferredprepass = true;
4436 r_shadow_prepass_width = vid.width;
4437 r_shadow_prepass_height = vid.height;
4438 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4439 switch (vid.renderpath)
4441 case RENDERPATH_D3D9:
4442 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);
4447 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);
4448 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);
4449 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);
4451 // set up the geometry pass fbo (depth + normalmap)
4452 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4453 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4454 // render depth into one texture and normalmap into the other
4455 if (qglDrawBuffersARB)
4457 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4458 qglReadBuffer(GL_NONE);CHECKGLERROR
4459 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4460 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4462 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4463 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4464 r_shadow_usingdeferredprepass = false;
4468 // set up the lighting pass fbo (diffuse + specular)
4469 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4470 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4471 // render diffuse into one texture and specular into another,
4472 // with depth and normalmap bound as textures,
4473 // with depth bound as attachment as well
4474 if (qglDrawBuffersARB)
4476 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4477 qglReadBuffer(GL_NONE);CHECKGLERROR
4478 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4479 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4481 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4482 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4483 r_shadow_usingdeferredprepass = false;
4487 // set up the lighting pass fbo (diffuse)
4488 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4489 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4490 // render diffuse into one texture,
4491 // with depth and normalmap bound as textures,
4492 // with depth bound as attachment as well
4493 if (qglDrawBuffersARB)
4495 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4496 qglReadBuffer(GL_NONE);CHECKGLERROR
4497 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4498 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4500 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4501 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4502 r_shadow_usingdeferredprepass = false;
4507 case RENDERPATH_GL13:
4508 case RENDERPATH_GL11:
4509 r_shadow_usingdeferredprepass = false;
4513 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);
4515 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4516 if (r_shadow_debuglight.integer >= 0)
4518 lightindex = r_shadow_debuglight.integer;
4519 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4520 if (light && (light->flags & flag))
4521 R_Shadow_PrepareLight(&light->rtlight);
4525 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4526 for (lightindex = 0;lightindex < range;lightindex++)
4528 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4529 if (light && (light->flags & flag))
4530 R_Shadow_PrepareLight(&light->rtlight);
4533 if (r_refdef.scene.rtdlight)
4535 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4536 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4538 else if(gl_flashblend.integer)
4540 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4542 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4543 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4544 VectorScale(rtlight->color, f, rtlight->currentcolor);
4548 if (r_editlights.integer)
4549 R_Shadow_DrawLightSprites();
4551 R_Shadow_UpdateBounceGridTexture();
4554 void R_Shadow_DrawLights(void)
4562 R_Shadow_RenderMode_Begin();
4564 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4565 if (r_shadow_debuglight.integer >= 0)
4567 lightindex = r_shadow_debuglight.integer;
4568 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4569 if (light && (light->flags & flag))
4570 R_Shadow_DrawLight(&light->rtlight);
4574 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4575 for (lightindex = 0;lightindex < range;lightindex++)
4577 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4578 if (light && (light->flags & flag))
4579 R_Shadow_DrawLight(&light->rtlight);
4582 if (r_refdef.scene.rtdlight)
4583 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4584 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4586 R_Shadow_RenderMode_End();
4589 extern const float r_screenvertex3f[12];
4590 extern void R_SetupView(qboolean allowwaterclippingplane);
4591 extern void R_ResetViewRendering3D(void);
4592 extern void R_ResetViewRendering2D(void);
4593 extern cvar_t r_shadows;
4594 extern cvar_t r_shadows_darken;
4595 extern cvar_t r_shadows_drawafterrtlighting;
4596 extern cvar_t r_shadows_castfrombmodels;
4597 extern cvar_t r_shadows_throwdistance;
4598 extern cvar_t r_shadows_throwdirection;
4599 extern cvar_t r_shadows_focus;
4600 extern cvar_t r_shadows_shadowmapscale;
4602 void R_Shadow_PrepareModelShadows(void)
4605 float scale, size, radius, dot1, dot2;
4606 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4607 entity_render_t *ent;
4609 if (!r_refdef.scene.numentities)
4612 switch (r_shadow_shadowmode)
4614 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4615 if (r_shadows.integer >= 2)
4618 case R_SHADOW_SHADOWMODE_STENCIL:
4619 for (i = 0;i < r_refdef.scene.numentities;i++)
4621 ent = r_refdef.scene.entities[i];
4622 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4623 R_AnimCache_GetEntity(ent, false, false);
4630 size = 2*r_shadow_shadowmapmaxsize;
4631 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4632 radius = 0.5f * size / scale;
4634 Math_atov(r_shadows_throwdirection.string, shadowdir);
4635 VectorNormalize(shadowdir);
4636 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4637 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4638 if (fabs(dot1) <= fabs(dot2))
4639 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4641 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4642 VectorNormalize(shadowforward);
4643 CrossProduct(shadowdir, shadowforward, shadowright);
4644 Math_atov(r_shadows_focus.string, shadowfocus);
4645 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4646 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4647 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4648 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4649 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4651 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4653 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4654 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4655 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4656 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4657 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4658 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4660 for (i = 0;i < r_refdef.scene.numentities;i++)
4662 ent = r_refdef.scene.entities[i];
4663 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4665 // cast shadows from anything of the map (submodels are optional)
4666 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4667 R_AnimCache_GetEntity(ent, false, false);
4671 void R_DrawModelShadowMaps(void)
4674 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4675 entity_render_t *ent;
4676 vec3_t relativelightorigin;
4677 vec3_t relativelightdirection, relativeforward, relativeright;
4678 vec3_t relativeshadowmins, relativeshadowmaxs;
4679 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4681 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4682 r_viewport_t viewport;
4684 float clearcolor[4];
4686 if (!r_refdef.scene.numentities)
4689 switch (r_shadow_shadowmode)
4691 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4697 R_ResetViewRendering3D();
4698 R_Shadow_RenderMode_Begin();
4699 R_Shadow_RenderMode_ActiveLight(NULL);
4701 switch (r_shadow_shadowmode)
4703 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4704 if (!r_shadow_shadowmap2dtexture)
4705 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4706 fbo = r_shadow_fbo2d;
4707 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4708 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4709 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4715 size = 2*r_shadow_shadowmapmaxsize;
4716 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4717 radius = 0.5f / scale;
4718 nearclip = -r_shadows_throwdistance.value;
4719 farclip = r_shadows_throwdistance.value;
4720 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4722 r_shadow_shadowmap_parameters[0] = size;
4723 r_shadow_shadowmap_parameters[1] = size;
4724 r_shadow_shadowmap_parameters[2] = 1.0;
4725 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4727 Math_atov(r_shadows_throwdirection.string, shadowdir);
4728 VectorNormalize(shadowdir);
4729 Math_atov(r_shadows_focus.string, shadowfocus);
4730 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4731 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4732 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4733 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4734 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4735 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4736 if (fabs(dot1) <= fabs(dot2))
4737 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4739 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4740 VectorNormalize(shadowforward);
4741 VectorM(scale, shadowforward, &m[0]);
4742 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4744 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4745 CrossProduct(shadowdir, shadowforward, shadowright);
4746 VectorM(scale, shadowright, &m[4]);
4747 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4748 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4749 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4750 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4751 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4752 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4754 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4756 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
4757 R_SetupShader_DepthOrShadow();
4758 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4761 R_SetViewport(&viewport);
4762 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4763 Vector4Set(clearcolor, 1,1,1,1);
4764 // in D3D9 we have to render to a color texture shadowmap
4765 // in GL we render directly to a depth texture only
4766 if (r_shadow_shadowmap2dtexture)
4767 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4769 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4770 // render into a slightly restricted region so that the borders of the
4771 // shadowmap area fade away, rather than streaking across everything
4772 // outside the usable area
4773 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4777 R_Mesh_ResetRenderTargets();
4778 R_SetupShader_ShowDepth();
4779 GL_ColorMask(1,1,1,1);
4780 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4783 for (i = 0;i < r_refdef.scene.numentities;i++)
4785 ent = r_refdef.scene.entities[i];
4787 // cast shadows from anything of the map (submodels are optional)
4788 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4790 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4791 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4792 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4793 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4794 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4795 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4796 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4797 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4798 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4799 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4800 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4801 RSurf_ActiveModelEntity(ent, false, false, false);
4802 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4803 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4810 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4812 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4814 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4815 Cvar_SetValueQuick(&r_test, 0);
4820 R_Shadow_RenderMode_End();
4822 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4823 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4824 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4825 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4826 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4827 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4829 switch (vid.renderpath)
4831 case RENDERPATH_GL11:
4832 case RENDERPATH_GL13:
4833 case RENDERPATH_GL20:
4834 case RENDERPATH_SOFT:
4835 case RENDERPATH_GLES2:
4837 case RENDERPATH_D3D9:
4838 case RENDERPATH_D3D10:
4839 case RENDERPATH_D3D11:
4840 #ifdef OPENGL_ORIENTATION
4841 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4842 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
4843 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
4844 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
4846 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4847 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
4848 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
4849 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
4854 r_shadow_usingshadowmaportho = true;
4855 switch (r_shadow_shadowmode)
4857 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4858 r_shadow_usingshadowmap2d = true;
4865 void R_DrawModelShadows(void)
4868 float relativethrowdistance;
4869 entity_render_t *ent;
4870 vec3_t relativelightorigin;
4871 vec3_t relativelightdirection;
4872 vec3_t relativeshadowmins, relativeshadowmaxs;
4873 vec3_t tmp, shadowdir;
4875 if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4878 R_ResetViewRendering3D();
4879 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4880 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4881 R_Shadow_RenderMode_Begin();
4882 R_Shadow_RenderMode_ActiveLight(NULL);
4883 r_shadow_lightscissor[0] = r_refdef.view.x;
4884 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4885 r_shadow_lightscissor[2] = r_refdef.view.width;
4886 r_shadow_lightscissor[3] = r_refdef.view.height;
4887 R_Shadow_RenderMode_StencilShadowVolumes(false);
4890 if (r_shadows.integer == 2)
4892 Math_atov(r_shadows_throwdirection.string, shadowdir);
4893 VectorNormalize(shadowdir);
4896 R_Shadow_ClearStencil();
4898 for (i = 0;i < r_refdef.scene.numentities;i++)
4900 ent = r_refdef.scene.entities[i];
4902 // cast shadows from anything of the map (submodels are optional)
4903 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4905 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4906 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4907 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4908 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4909 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4912 if(ent->entitynumber != 0)
4914 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4916 // FIXME handle this
4917 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4921 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4922 int entnum, entnum2, recursion;
4923 entnum = entnum2 = ent->entitynumber;
4924 for(recursion = 32; recursion > 0; --recursion)
4926 entnum2 = cl.entities[entnum].state_current.tagentity;
4927 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4932 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4934 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4935 // transform into modelspace of OUR entity
4936 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4937 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4940 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4944 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4947 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4948 RSurf_ActiveModelEntity(ent, false, false, false);
4949 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4950 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4954 // not really the right mode, but this will disable any silly stencil features
4955 R_Shadow_RenderMode_End();
4957 // set up ortho view for rendering this pass
4958 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4959 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4960 //GL_ScissorTest(true);
4961 //R_EntityMatrix(&identitymatrix);
4962 //R_Mesh_ResetTextureState();
4963 R_ResetViewRendering2D();
4965 // set up a darkening blend on shadowed areas
4966 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4967 //GL_DepthRange(0, 1);
4968 //GL_DepthTest(false);
4969 //GL_DepthMask(false);
4970 //GL_PolygonOffset(0, 0);CHECKGLERROR
4971 GL_Color(0, 0, 0, r_shadows_darken.value);
4972 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4973 //GL_DepthFunc(GL_ALWAYS);
4974 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
4976 // apply the blend to the shadowed areas
4977 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
4978 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4979 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4981 // restore the viewport
4982 R_SetViewport(&r_refdef.view.viewport);
4984 // restore other state to normal
4985 //R_Shadow_RenderMode_End();
4988 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4991 vec3_t centerorigin;
4993 // if it's too close, skip it
4994 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4996 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4999 if (usequery && r_numqueries + 2 <= r_maxqueries)
5001 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5002 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5003 // 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
5004 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5006 switch(vid.renderpath)
5008 case RENDERPATH_GL20:
5009 case RENDERPATH_GL13:
5010 case RENDERPATH_GL11:
5011 case RENDERPATH_GLES2:
5013 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5014 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5015 GL_DepthFunc(GL_ALWAYS);
5016 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5017 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
5018 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5019 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5020 GL_DepthFunc(GL_LEQUAL);
5021 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5022 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5023 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
5024 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5025 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5028 case RENDERPATH_D3D9:
5029 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5031 case RENDERPATH_D3D10:
5032 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5034 case RENDERPATH_D3D11:
5035 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5037 case RENDERPATH_SOFT:
5038 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5042 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5045 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5047 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5050 GLint allpixels = 0, visiblepixels = 0;
5051 // now we have to check the query result
5052 if (rtlight->corona_queryindex_visiblepixels)
5054 switch(vid.renderpath)
5056 case RENDERPATH_GL20:
5057 case RENDERPATH_GL13:
5058 case RENDERPATH_GL11:
5059 case RENDERPATH_GLES2:
5061 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5062 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5065 case RENDERPATH_D3D9:
5066 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5068 case RENDERPATH_D3D10:
5069 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5071 case RENDERPATH_D3D11:
5072 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5074 case RENDERPATH_SOFT:
5075 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5078 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
5079 if (visiblepixels < 1 || allpixels < 1)
5081 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5082 cscale *= rtlight->corona_visibility;
5086 // FIXME: these traces should scan all render entities instead of cl.world
5087 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
5090 VectorScale(rtlight->currentcolor, cscale, color);
5091 if (VectorLength(color) > (1.0f / 256.0f))
5094 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
5097 VectorNegate(color, color);
5098 switch(vid.renderpath)
5100 case RENDERPATH_GL11:
5101 case RENDERPATH_GL13:
5102 case RENDERPATH_GL20:
5103 case RENDERPATH_GLES2:
5104 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
5106 case RENDERPATH_D3D9:
5108 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
5111 case RENDERPATH_D3D10:
5112 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5114 case RENDERPATH_D3D11:
5115 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5117 case RENDERPATH_SOFT:
5118 DPSOFTRAST_BlendSubtract(true);
5122 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5123 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);
5124 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5127 switch(vid.renderpath)
5129 case RENDERPATH_GL11:
5130 case RENDERPATH_GL13:
5131 case RENDERPATH_GL20:
5132 case RENDERPATH_GLES2:
5133 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
5135 case RENDERPATH_D3D9:
5137 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
5140 case RENDERPATH_D3D10:
5141 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5143 case RENDERPATH_D3D11:
5144 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5146 case RENDERPATH_SOFT:
5147 DPSOFTRAST_BlendSubtract(false);
5154 void R_Shadow_DrawCoronas(void)
5157 qboolean usequery = false;
5162 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
5164 if (r_waterstate.renderingscene)
5166 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5167 R_EntityMatrix(&identitymatrix);
5169 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5171 // check occlusion of coronas
5172 // use GL_ARB_occlusion_query if available
5173 // otherwise use raytraces
5175 switch (vid.renderpath)
5177 case RENDERPATH_GL11:
5178 case RENDERPATH_GL13:
5179 case RENDERPATH_GL20:
5180 case RENDERPATH_GLES2:
5181 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
5184 GL_ColorMask(0,0,0,0);
5185 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
5186 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
5189 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
5190 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
5192 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
5195 RSurf_ActiveWorldEntity();
5196 GL_BlendFunc(GL_ONE, GL_ZERO);
5197 GL_CullFace(GL_NONE);
5198 GL_DepthMask(false);
5199 GL_DepthRange(0, 1);
5200 GL_PolygonOffset(0, 0);
5202 R_Mesh_ResetTextureState();
5203 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
5206 case RENDERPATH_D3D9:
5208 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5210 case RENDERPATH_D3D10:
5211 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5213 case RENDERPATH_D3D11:
5214 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5216 case RENDERPATH_SOFT:
5218 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5221 for (lightindex = 0;lightindex < range;lightindex++)
5223 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5226 rtlight = &light->rtlight;
5227 rtlight->corona_visibility = 0;
5228 rtlight->corona_queryindex_visiblepixels = 0;
5229 rtlight->corona_queryindex_allpixels = 0;
5230 if (!(rtlight->flags & flag))
5232 if (rtlight->corona <= 0)
5234 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
5236 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5238 for (i = 0;i < r_refdef.scene.numlights;i++)
5240 rtlight = r_refdef.scene.lights[i];
5241 rtlight->corona_visibility = 0;
5242 rtlight->corona_queryindex_visiblepixels = 0;
5243 rtlight->corona_queryindex_allpixels = 0;
5244 if (!(rtlight->flags & flag))
5246 if (rtlight->corona <= 0)
5248 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5251 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5253 // now draw the coronas using the query data for intensity info
5254 for (lightindex = 0;lightindex < range;lightindex++)
5256 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5259 rtlight = &light->rtlight;
5260 if (rtlight->corona_visibility <= 0)
5262 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5264 for (i = 0;i < r_refdef.scene.numlights;i++)
5266 rtlight = r_refdef.scene.lights[i];
5267 if (rtlight->corona_visibility <= 0)
5269 if (gl_flashblend.integer)
5270 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
5272 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5278 dlight_t *R_Shadow_NewWorldLight(void)
5280 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
5283 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)
5286 // validate parameters
5287 if (style < 0 || style >= MAX_LIGHTSTYLES)
5289 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
5295 // copy to light properties
5296 VectorCopy(origin, light->origin);
5297 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
5298 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
5299 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
5301 light->color[0] = max(color[0], 0);
5302 light->color[1] = max(color[1], 0);
5303 light->color[2] = max(color[2], 0);
5305 light->color[0] = color[0];
5306 light->color[1] = color[1];
5307 light->color[2] = color[2];
5308 light->radius = max(radius, 0);
5309 light->style = style;
5310 light->shadow = shadowenable;
5311 light->corona = corona;
5312 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
5313 light->coronasizescale = coronasizescale;
5314 light->ambientscale = ambientscale;
5315 light->diffusescale = diffusescale;
5316 light->specularscale = specularscale;
5317 light->flags = flags;
5319 // update renderable light data
5320 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
5321 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);
5324 void R_Shadow_FreeWorldLight(dlight_t *light)
5326 if (r_shadow_selectedlight == light)
5327 r_shadow_selectedlight = NULL;
5328 R_RTLight_Uncompile(&light->rtlight);
5329 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
5332 void R_Shadow_ClearWorldLights(void)
5336 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5337 for (lightindex = 0;lightindex < range;lightindex++)
5339 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5341 R_Shadow_FreeWorldLight(light);
5343 r_shadow_selectedlight = NULL;
5346 void R_Shadow_SelectLight(dlight_t *light)
5348 if (r_shadow_selectedlight)
5349 r_shadow_selectedlight->selected = false;
5350 r_shadow_selectedlight = light;
5351 if (r_shadow_selectedlight)
5352 r_shadow_selectedlight->selected = true;
5355 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5357 // this is never batched (there can be only one)
5359 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
5360 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5361 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5364 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5369 skinframe_t *skinframe;
5372 // this is never batched (due to the ent parameter changing every time)
5373 // so numsurfaces == 1 and surfacelist[0] == lightnumber
5374 const dlight_t *light = (dlight_t *)ent;
5377 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
5380 VectorScale(light->color, intensity, spritecolor);
5381 if (VectorLength(spritecolor) < 0.1732f)
5382 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
5383 if (VectorLength(spritecolor) > 1.0f)
5384 VectorNormalize(spritecolor);
5386 // draw light sprite
5387 if (light->cubemapname[0] && !light->shadow)
5388 skinframe = r_editlights_sprcubemapnoshadowlight;
5389 else if (light->cubemapname[0])
5390 skinframe = r_editlights_sprcubemaplight;
5391 else if (!light->shadow)
5392 skinframe = r_editlights_sprnoshadowlight;
5394 skinframe = r_editlights_sprlight;
5396 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);
5397 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5399 // draw selection sprite if light is selected
5400 if (light->selected)
5402 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5403 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5404 // VorteX todo: add normalmode/realtime mode light overlay sprites?
5408 void R_Shadow_DrawLightSprites(void)
5412 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5413 for (lightindex = 0;lightindex < range;lightindex++)
5415 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5417 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
5419 if (!r_editlights_lockcursor)
5420 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
5423 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
5428 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
5429 if (lightindex >= range)
5431 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5434 rtlight = &light->rtlight;
5435 //if (!(rtlight->flags & flag))
5437 VectorCopy(rtlight->shadoworigin, origin);
5438 *radius = rtlight->radius;
5439 VectorCopy(rtlight->color, color);
5443 void R_Shadow_SelectLightInView(void)
5445 float bestrating, rating, temp[3];
5449 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5453 if (r_editlights_lockcursor)
5455 for (lightindex = 0;lightindex < range;lightindex++)
5457 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5460 VectorSubtract(light->origin, r_refdef.view.origin, temp);
5461 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
5464 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
5465 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
5467 bestrating = rating;
5472 R_Shadow_SelectLight(best);
5475 void R_Shadow_LoadWorldLights(void)
5477 int n, a, style, shadow, flags;
5478 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
5479 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
5480 if (cl.worldmodel == NULL)
5482 Con_Print("No map loaded.\n");
5485 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5486 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5496 for (;COM_Parse(t, true) && strcmp(
5497 if (COM_Parse(t, true))
5499 if (com_token[0] == '!')
5502 origin[0] = atof(com_token+1);
5505 origin[0] = atof(com_token);
5510 while (*s && *s != '\n' && *s != '\r')
5516 // check for modifier flags
5523 #if _MSC_VER >= 1400
5524 #define sscanf sscanf_s
5526 cubemapname[sizeof(cubemapname)-1] = 0;
5527 #if MAX_QPATH != 128
5528 #error update this code if MAX_QPATH changes
5530 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
5531 #if _MSC_VER >= 1400
5532 , sizeof(cubemapname)
5534 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5537 flags = LIGHTFLAG_REALTIMEMODE;
5545 coronasizescale = 0.25f;
5547 VectorClear(angles);
5550 if (a < 9 || !strcmp(cubemapname, "\"\""))
5552 // remove quotes on cubemapname
5553 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5556 namelen = strlen(cubemapname) - 2;
5557 memmove(cubemapname, cubemapname + 1, namelen);
5558 cubemapname[namelen] = '\0';
5562 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);
5565 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5573 Con_Printf("invalid rtlights file \"%s\"\n", name);
5574 Mem_Free(lightsstring);
5578 void R_Shadow_SaveWorldLights(void)
5582 size_t bufchars, bufmaxchars;
5584 char name[MAX_QPATH];
5585 char line[MAX_INPUTLINE];
5586 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5587 // I hate lines which are 3 times my screen size :( --blub
5590 if (cl.worldmodel == NULL)
5592 Con_Print("No map loaded.\n");
5595 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5596 bufchars = bufmaxchars = 0;
5598 for (lightindex = 0;lightindex < range;lightindex++)
5600 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5603 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5604 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);
5605 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5606 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]);
5608 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);
5609 if (bufchars + strlen(line) > bufmaxchars)
5611 bufmaxchars = bufchars + strlen(line) + 2048;
5613 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5617 memcpy(buf, oldbuf, bufchars);
5623 memcpy(buf + bufchars, line, strlen(line));
5624 bufchars += strlen(line);
5628 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5633 void R_Shadow_LoadLightsFile(void)
5636 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5637 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5638 if (cl.worldmodel == NULL)
5640 Con_Print("No map loaded.\n");
5643 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5644 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5652 while (*s && *s != '\n' && *s != '\r')
5658 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);
5662 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);
5665 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5666 radius = bound(15, radius, 4096);
5667 VectorScale(color, (2.0f / (8388608.0f)), color);
5668 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5676 Con_Printf("invalid lights file \"%s\"\n", name);
5677 Mem_Free(lightsstring);
5681 // tyrlite/hmap2 light types in the delay field
5682 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5684 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5696 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5697 char key[256], value[MAX_INPUTLINE];
5699 if (cl.worldmodel == NULL)
5701 Con_Print("No map loaded.\n");
5704 // try to load a .ent file first
5705 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5706 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5707 // and if that is not found, fall back to the bsp file entity string
5709 data = cl.worldmodel->brush.entities;
5712 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5714 type = LIGHTTYPE_MINUSX;
5715 origin[0] = origin[1] = origin[2] = 0;
5716 originhack[0] = originhack[1] = originhack[2] = 0;
5717 angles[0] = angles[1] = angles[2] = 0;
5718 color[0] = color[1] = color[2] = 1;
5719 light[0] = light[1] = light[2] = 1;light[3] = 300;
5720 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5730 if (!COM_ParseToken_Simple(&data, false, false))
5732 if (com_token[0] == '}')
5733 break; // end of entity
5734 if (com_token[0] == '_')
5735 strlcpy(key, com_token + 1, sizeof(key));
5737 strlcpy(key, com_token, sizeof(key));
5738 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5739 key[strlen(key)-1] = 0;
5740 if (!COM_ParseToken_Simple(&data, false, false))
5742 strlcpy(value, com_token, sizeof(value));
5744 // now that we have the key pair worked out...
5745 if (!strcmp("light", key))
5747 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5751 light[0] = vec[0] * (1.0f / 256.0f);
5752 light[1] = vec[0] * (1.0f / 256.0f);
5753 light[2] = vec[0] * (1.0f / 256.0f);
5759 light[0] = vec[0] * (1.0f / 255.0f);
5760 light[1] = vec[1] * (1.0f / 255.0f);
5761 light[2] = vec[2] * (1.0f / 255.0f);
5765 else if (!strcmp("delay", key))
5767 else if (!strcmp("origin", key))
5768 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5769 else if (!strcmp("angle", key))
5770 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5771 else if (!strcmp("angles", key))
5772 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5773 else if (!strcmp("color", key))
5774 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5775 else if (!strcmp("wait", key))
5776 fadescale = atof(value);
5777 else if (!strcmp("classname", key))
5779 if (!strncmp(value, "light", 5))
5782 if (!strcmp(value, "light_fluoro"))
5787 overridecolor[0] = 1;
5788 overridecolor[1] = 1;
5789 overridecolor[2] = 1;
5791 if (!strcmp(value, "light_fluorospark"))
5796 overridecolor[0] = 1;
5797 overridecolor[1] = 1;
5798 overridecolor[2] = 1;
5800 if (!strcmp(value, "light_globe"))
5805 overridecolor[0] = 1;
5806 overridecolor[1] = 0.8;
5807 overridecolor[2] = 0.4;
5809 if (!strcmp(value, "light_flame_large_yellow"))
5814 overridecolor[0] = 1;
5815 overridecolor[1] = 0.5;
5816 overridecolor[2] = 0.1;
5818 if (!strcmp(value, "light_flame_small_yellow"))
5823 overridecolor[0] = 1;
5824 overridecolor[1] = 0.5;
5825 overridecolor[2] = 0.1;
5827 if (!strcmp(value, "light_torch_small_white"))
5832 overridecolor[0] = 1;
5833 overridecolor[1] = 0.5;
5834 overridecolor[2] = 0.1;
5836 if (!strcmp(value, "light_torch_small_walltorch"))
5841 overridecolor[0] = 1;
5842 overridecolor[1] = 0.5;
5843 overridecolor[2] = 0.1;
5847 else if (!strcmp("style", key))
5848 style = atoi(value);
5849 else if (!strcmp("skin", key))
5850 skin = (int)atof(value);
5851 else if (!strcmp("pflags", key))
5852 pflags = (int)atof(value);
5853 //else if (!strcmp("effects", key))
5854 // effects = (int)atof(value);
5855 else if (cl.worldmodel->type == mod_brushq3)
5857 if (!strcmp("scale", key))
5858 lightscale = atof(value);
5859 if (!strcmp("fade", key))
5860 fadescale = atof(value);
5865 if (lightscale <= 0)
5869 if (color[0] == color[1] && color[0] == color[2])
5871 color[0] *= overridecolor[0];
5872 color[1] *= overridecolor[1];
5873 color[2] *= overridecolor[2];
5875 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5876 color[0] = color[0] * light[0];
5877 color[1] = color[1] * light[1];
5878 color[2] = color[2] * light[2];
5881 case LIGHTTYPE_MINUSX:
5883 case LIGHTTYPE_RECIPX:
5885 VectorScale(color, (1.0f / 16.0f), color);
5887 case LIGHTTYPE_RECIPXX:
5889 VectorScale(color, (1.0f / 16.0f), color);
5892 case LIGHTTYPE_NONE:
5896 case LIGHTTYPE_MINUSXX:
5899 VectorAdd(origin, originhack, origin);
5901 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);
5904 Mem_Free(entfiledata);
5908 void R_Shadow_SetCursorLocationForView(void)
5911 vec3_t dest, endpos;
5913 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5914 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5915 if (trace.fraction < 1)
5917 dist = trace.fraction * r_editlights_cursordistance.value;
5918 push = r_editlights_cursorpushback.value;
5922 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5923 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5927 VectorClear( endpos );
5929 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5930 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5931 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5934 void R_Shadow_UpdateWorldLightSelection(void)
5936 if (r_editlights.integer)
5938 R_Shadow_SetCursorLocationForView();
5939 R_Shadow_SelectLightInView();
5942 R_Shadow_SelectLight(NULL);
5945 void R_Shadow_EditLights_Clear_f(void)
5947 R_Shadow_ClearWorldLights();
5950 void R_Shadow_EditLights_Reload_f(void)
5954 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5955 R_Shadow_ClearWorldLights();
5956 R_Shadow_LoadWorldLights();
5957 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5959 R_Shadow_LoadLightsFile();
5960 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5961 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5965 void R_Shadow_EditLights_Save_f(void)
5969 R_Shadow_SaveWorldLights();
5972 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5974 R_Shadow_ClearWorldLights();
5975 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5978 void R_Shadow_EditLights_ImportLightsFile_f(void)
5980 R_Shadow_ClearWorldLights();
5981 R_Shadow_LoadLightsFile();
5984 void R_Shadow_EditLights_Spawn_f(void)
5987 if (!r_editlights.integer)
5989 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5992 if (Cmd_Argc() != 1)
5994 Con_Print("r_editlights_spawn does not take parameters\n");
5997 color[0] = color[1] = color[2] = 1;
5998 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6001 void R_Shadow_EditLights_Edit_f(void)
6003 vec3_t origin, angles, color;
6004 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6005 int style, shadows, flags, normalmode, realtimemode;
6006 char cubemapname[MAX_INPUTLINE];
6007 if (!r_editlights.integer)
6009 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6012 if (!r_shadow_selectedlight)
6014 Con_Print("No selected light.\n");
6017 VectorCopy(r_shadow_selectedlight->origin, origin);
6018 VectorCopy(r_shadow_selectedlight->angles, angles);
6019 VectorCopy(r_shadow_selectedlight->color, color);
6020 radius = r_shadow_selectedlight->radius;
6021 style = r_shadow_selectedlight->style;
6022 if (r_shadow_selectedlight->cubemapname)
6023 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6026 shadows = r_shadow_selectedlight->shadow;
6027 corona = r_shadow_selectedlight->corona;
6028 coronasizescale = r_shadow_selectedlight->coronasizescale;
6029 ambientscale = r_shadow_selectedlight->ambientscale;
6030 diffusescale = r_shadow_selectedlight->diffusescale;
6031 specularscale = r_shadow_selectedlight->specularscale;
6032 flags = r_shadow_selectedlight->flags;
6033 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6034 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6035 if (!strcmp(Cmd_Argv(1), "origin"))
6037 if (Cmd_Argc() != 5)
6039 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6042 origin[0] = atof(Cmd_Argv(2));
6043 origin[1] = atof(Cmd_Argv(3));
6044 origin[2] = atof(Cmd_Argv(4));
6046 else if (!strcmp(Cmd_Argv(1), "originx"))
6048 if (Cmd_Argc() != 3)
6050 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6053 origin[0] = atof(Cmd_Argv(2));
6055 else if (!strcmp(Cmd_Argv(1), "originy"))
6057 if (Cmd_Argc() != 3)
6059 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6062 origin[1] = atof(Cmd_Argv(2));
6064 else if (!strcmp(Cmd_Argv(1), "originz"))
6066 if (Cmd_Argc() != 3)
6068 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6071 origin[2] = atof(Cmd_Argv(2));
6073 else if (!strcmp(Cmd_Argv(1), "move"))
6075 if (Cmd_Argc() != 5)
6077 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6080 origin[0] += atof(Cmd_Argv(2));
6081 origin[1] += atof(Cmd_Argv(3));
6082 origin[2] += atof(Cmd_Argv(4));
6084 else if (!strcmp(Cmd_Argv(1), "movex"))
6086 if (Cmd_Argc() != 3)
6088 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6091 origin[0] += atof(Cmd_Argv(2));
6093 else if (!strcmp(Cmd_Argv(1), "movey"))
6095 if (Cmd_Argc() != 3)
6097 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6100 origin[1] += atof(Cmd_Argv(2));
6102 else if (!strcmp(Cmd_Argv(1), "movez"))
6104 if (Cmd_Argc() != 3)
6106 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6109 origin[2] += atof(Cmd_Argv(2));
6111 else if (!strcmp(Cmd_Argv(1), "angles"))
6113 if (Cmd_Argc() != 5)
6115 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6118 angles[0] = atof(Cmd_Argv(2));
6119 angles[1] = atof(Cmd_Argv(3));
6120 angles[2] = atof(Cmd_Argv(4));
6122 else if (!strcmp(Cmd_Argv(1), "anglesx"))
6124 if (Cmd_Argc() != 3)
6126 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6129 angles[0] = atof(Cmd_Argv(2));
6131 else if (!strcmp(Cmd_Argv(1), "anglesy"))
6133 if (Cmd_Argc() != 3)
6135 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6138 angles[1] = atof(Cmd_Argv(2));
6140 else if (!strcmp(Cmd_Argv(1), "anglesz"))
6142 if (Cmd_Argc() != 3)
6144 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6147 angles[2] = atof(Cmd_Argv(2));
6149 else if (!strcmp(Cmd_Argv(1), "color"))
6151 if (Cmd_Argc() != 5)
6153 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
6156 color[0] = atof(Cmd_Argv(2));
6157 color[1] = atof(Cmd_Argv(3));
6158 color[2] = atof(Cmd_Argv(4));
6160 else if (!strcmp(Cmd_Argv(1), "radius"))
6162 if (Cmd_Argc() != 3)
6164 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6167 radius = atof(Cmd_Argv(2));
6169 else if (!strcmp(Cmd_Argv(1), "colorscale"))
6171 if (Cmd_Argc() == 3)
6173 double scale = atof(Cmd_Argv(2));
6180 if (Cmd_Argc() != 5)
6182 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
6185 color[0] *= atof(Cmd_Argv(2));
6186 color[1] *= atof(Cmd_Argv(3));
6187 color[2] *= atof(Cmd_Argv(4));
6190 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
6192 if (Cmd_Argc() != 3)
6194 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6197 radius *= atof(Cmd_Argv(2));
6199 else if (!strcmp(Cmd_Argv(1), "style"))
6201 if (Cmd_Argc() != 3)
6203 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6206 style = atoi(Cmd_Argv(2));
6208 else if (!strcmp(Cmd_Argv(1), "cubemap"))
6212 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6215 if (Cmd_Argc() == 3)
6216 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
6220 else if (!strcmp(Cmd_Argv(1), "shadows"))
6222 if (Cmd_Argc() != 3)
6224 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6227 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6229 else if (!strcmp(Cmd_Argv(1), "corona"))
6231 if (Cmd_Argc() != 3)
6233 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6236 corona = atof(Cmd_Argv(2));
6238 else if (!strcmp(Cmd_Argv(1), "coronasize"))
6240 if (Cmd_Argc() != 3)
6242 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6245 coronasizescale = atof(Cmd_Argv(2));
6247 else if (!strcmp(Cmd_Argv(1), "ambient"))
6249 if (Cmd_Argc() != 3)
6251 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6254 ambientscale = atof(Cmd_Argv(2));
6256 else if (!strcmp(Cmd_Argv(1), "diffuse"))
6258 if (Cmd_Argc() != 3)
6260 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6263 diffusescale = atof(Cmd_Argv(2));
6265 else if (!strcmp(Cmd_Argv(1), "specular"))
6267 if (Cmd_Argc() != 3)
6269 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6272 specularscale = atof(Cmd_Argv(2));
6274 else if (!strcmp(Cmd_Argv(1), "normalmode"))
6276 if (Cmd_Argc() != 3)
6278 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6281 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6283 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
6285 if (Cmd_Argc() != 3)
6287 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6290 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6294 Con_Print("usage: r_editlights_edit [property] [value]\n");
6295 Con_Print("Selected light's properties:\n");
6296 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6297 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6298 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6299 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
6300 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
6301 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
6302 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
6303 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
6304 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
6305 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
6306 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
6307 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
6308 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
6309 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
6312 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
6313 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6316 void R_Shadow_EditLights_EditAll_f(void)
6319 dlight_t *light, *oldselected;
6322 if (!r_editlights.integer)
6324 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
6328 oldselected = r_shadow_selectedlight;
6329 // EditLights doesn't seem to have a "remove" command or something so:
6330 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6331 for (lightindex = 0;lightindex < range;lightindex++)
6333 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6336 R_Shadow_SelectLight(light);
6337 R_Shadow_EditLights_Edit_f();
6339 // return to old selected (to not mess editing once selection is locked)
6340 R_Shadow_SelectLight(oldselected);
6343 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
6345 int lightnumber, lightcount;
6346 size_t lightindex, range;
6350 if (!r_editlights.integer)
6352 x = vid_conwidth.value - 240;
6354 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
6357 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6358 for (lightindex = 0;lightindex < range;lightindex++)
6360 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6363 if (light == r_shadow_selectedlight)
6364 lightnumber = lightindex;
6367 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;
6368 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;
6370 if (r_shadow_selectedlight == NULL)
6372 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;
6373 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;
6374 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;
6375 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;
6376 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;
6377 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;
6378 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;
6379 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;
6380 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;
6381 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;
6382 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;
6383 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;
6384 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;
6385 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;
6386 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;
6389 void R_Shadow_EditLights_ToggleShadow_f(void)
6391 if (!r_editlights.integer)
6393 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6396 if (!r_shadow_selectedlight)
6398 Con_Print("No selected light.\n");
6401 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);
6404 void R_Shadow_EditLights_ToggleCorona_f(void)
6406 if (!r_editlights.integer)
6408 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6411 if (!r_shadow_selectedlight)
6413 Con_Print("No selected light.\n");
6416 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);
6419 void R_Shadow_EditLights_Remove_f(void)
6421 if (!r_editlights.integer)
6423 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
6426 if (!r_shadow_selectedlight)
6428 Con_Print("No selected light.\n");
6431 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
6432 r_shadow_selectedlight = NULL;
6435 void R_Shadow_EditLights_Help_f(void)
6438 "Documentation on r_editlights system:\n"
6440 "r_editlights : enable/disable editing mode\n"
6441 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
6442 "r_editlights_cursorpushback : push back cursor this far from surface\n"
6443 "r_editlights_cursorpushoff : push cursor off surface this far\n"
6444 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
6445 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
6447 "r_editlights_help : this help\n"
6448 "r_editlights_clear : remove all lights\n"
6449 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
6450 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
6451 "r_editlights_save : save to .rtlights file\n"
6452 "r_editlights_spawn : create a light with default settings\n"
6453 "r_editlights_edit command : edit selected light - more documentation below\n"
6454 "r_editlights_remove : remove selected light\n"
6455 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
6456 "r_editlights_importlightentitiesfrommap : reload light entities\n"
6457 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
6459 "origin x y z : set light location\n"
6460 "originx x: set x component of light location\n"
6461 "originy y: set y component of light location\n"
6462 "originz z: set z component of light location\n"
6463 "move x y z : adjust light location\n"
6464 "movex x: adjust x component of light location\n"
6465 "movey y: adjust y component of light location\n"
6466 "movez z: adjust z component of light location\n"
6467 "angles x y z : set light angles\n"
6468 "anglesx x: set x component of light angles\n"
6469 "anglesy y: set y component of light angles\n"
6470 "anglesz z: set z component of light angles\n"
6471 "color r g b : set color of light (can be brighter than 1 1 1)\n"
6472 "radius radius : set radius (size) of light\n"
6473 "colorscale grey : multiply color of light (1 does nothing)\n"
6474 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
6475 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
6476 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
6477 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
6478 "cubemap basename : set filter cubemap of light (not yet supported)\n"
6479 "shadows 1/0 : turn on/off shadows\n"
6480 "corona n : set corona intensity\n"
6481 "coronasize n : set corona size (0-1)\n"
6482 "ambient n : set ambient intensity (0-1)\n"
6483 "diffuse n : set diffuse intensity (0-1)\n"
6484 "specular n : set specular intensity (0-1)\n"
6485 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6486 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6487 "<nothing> : print light properties to console\n"
6491 void R_Shadow_EditLights_CopyInfo_f(void)
6493 if (!r_editlights.integer)
6495 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
6498 if (!r_shadow_selectedlight)
6500 Con_Print("No selected light.\n");
6503 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6504 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6505 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6506 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6507 if (r_shadow_selectedlight->cubemapname)
6508 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6510 r_shadow_bufferlight.cubemapname[0] = 0;
6511 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6512 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6513 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6514 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6515 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6516 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6517 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6520 void R_Shadow_EditLights_PasteInfo_f(void)
6522 if (!r_editlights.integer)
6524 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6527 if (!r_shadow_selectedlight)
6529 Con_Print("No selected light.\n");
6532 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);
6535 void R_Shadow_EditLights_Lock_f(void)
6537 if (!r_editlights.integer)
6539 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6542 if (r_editlights_lockcursor)
6544 r_editlights_lockcursor = false;
6547 if (!r_shadow_selectedlight)
6549 Con_Print("No selected light to lock on.\n");
6552 r_editlights_lockcursor = true;
6555 void R_Shadow_EditLights_Init(void)
6557 Cvar_RegisterVariable(&r_editlights);
6558 Cvar_RegisterVariable(&r_editlights_cursordistance);
6559 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6560 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6561 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6562 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6563 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6564 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6565 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)");
6566 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6567 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6568 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6569 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)");
6570 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6571 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6572 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6573 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6574 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6575 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6576 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)");
6577 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6583 =============================================================================
6587 =============================================================================
6590 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
6592 int i, numlights, flag;
6595 float relativepoint[3];
6604 if (r_fullbright.integer)
6606 VectorSet(ambient, 1, 1, 1);
6607 VectorClear(diffuse);
6608 VectorClear(lightdir);
6612 if (flags & LP_LIGHTMAP)
6614 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6615 VectorClear(diffuse);
6616 VectorClear(lightdir);
6617 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6618 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
6622 memset(sample, 0, sizeof(sample));
6623 VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6625 if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6628 VectorClear(tempambient);
6630 VectorClear(relativepoint);
6631 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6632 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
6633 VectorScale(color, r_refdef.lightmapintensity, color);
6634 VectorAdd(sample, tempambient, sample);
6635 VectorMA(sample , 0.5f , color, sample );
6636 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6637 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6638 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6639 // calculate a weighted average light direction as well
6640 intensity = VectorLength(color);
6641 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6644 if (flags & LP_RTWORLD)
6646 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6647 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6648 for (i = 0; i < numlights; i++)
6650 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6653 light = &dlight->rtlight;
6654 if (!(light->flags & flag))
6657 lightradius2 = light->radius * light->radius;
6658 VectorSubtract(light->shadoworigin, p, relativepoint);
6659 dist2 = VectorLength2(relativepoint);
6660 if (dist2 >= lightradius2)
6662 dist = sqrt(dist2) / light->radius;
6663 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6664 if (intensity <= 0.0f)
6666 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
6668 // scale down intensity to add to both ambient and diffuse
6669 //intensity *= 0.5f;
6670 VectorNormalize(relativepoint);
6671 VectorScale(light->currentcolor, intensity, color);
6672 VectorMA(sample , 0.5f , color, sample );
6673 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6674 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6675 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6676 // calculate a weighted average light direction as well
6677 intensity *= VectorLength(color);
6678 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6682 if (flags & LP_DYNLIGHT)
6685 for (i = 0;i < r_refdef.scene.numlights;i++)
6687 light = r_refdef.scene.lights[i];
6689 lightradius2 = light->radius * light->radius;
6690 VectorSubtract(light->shadoworigin, p, relativepoint);
6691 dist2 = VectorLength2(relativepoint);
6692 if (dist2 >= lightradius2)
6694 dist = sqrt(dist2) / light->radius;
6695 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6696 if (intensity <= 0.0f)
6698 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
6700 // scale down intensity to add to both ambient and diffuse
6701 //intensity *= 0.5f;
6702 VectorNormalize(relativepoint);
6703 VectorScale(light->currentcolor, intensity, color);
6704 VectorMA(sample , 0.5f , color, sample );
6705 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6706 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6707 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6708 // calculate a weighted average light direction as well
6709 intensity *= VectorLength(color);
6710 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6714 // calculate the direction we'll use to reduce the sample to a directional light source
6715 VectorCopy(sample + 12, dir);
6716 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
6717 VectorNormalize(dir);
6718 // extract the diffuse color along the chosen direction and scale it
6719 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
6720 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
6721 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
6722 // subtract some of diffuse from ambient
6723 VectorMA(sample, -0.333f, diffuse, ambient);
6724 // store the normalized lightdir
6725 VectorCopy(dir, lightdir);