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", "3", "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", "4", "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];
366 static int r_shadow_bouncegridnumpixels;
367 static unsigned char *r_shadow_bouncegridpixels;
368 static unsigned short *r_shadow_bouncegridhighpixels;
370 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
371 #define ATTENTABLESIZE 256
372 // 1D gradient, 2D circle and 3D sphere attenuation textures
373 #define ATTEN1DSIZE 32
374 #define ATTEN2DSIZE 64
375 #define ATTEN3DSIZE 32
377 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
378 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
379 static float r_shadow_attentable[ATTENTABLESIZE+1];
381 rtlight_t *r_shadow_compilingrtlight;
382 static memexpandablearray_t r_shadow_worldlightsarray;
383 dlight_t *r_shadow_selectedlight;
384 dlight_t r_shadow_bufferlight;
385 vec3_t r_editlights_cursorlocation;
386 qboolean r_editlights_lockcursor;
388 extern int con_vislines;
390 void R_Shadow_UncompileWorldLights(void);
391 void R_Shadow_ClearWorldLights(void);
392 void R_Shadow_SaveWorldLights(void);
393 void R_Shadow_LoadWorldLights(void);
394 void R_Shadow_LoadLightsFile(void);
395 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
396 void R_Shadow_EditLights_Reload_f(void);
397 void R_Shadow_ValidateCvars(void);
398 static void R_Shadow_MakeTextures(void);
400 #define EDLIGHTSPRSIZE 8
401 skinframe_t *r_editlights_sprcursor;
402 skinframe_t *r_editlights_sprlight;
403 skinframe_t *r_editlights_sprnoshadowlight;
404 skinframe_t *r_editlights_sprcubemaplight;
405 skinframe_t *r_editlights_sprcubemapnoshadowlight;
406 skinframe_t *r_editlights_sprselection;
408 void R_Shadow_SetShadowMode(void)
410 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
411 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
412 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
413 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
414 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
415 r_shadow_shadowmaplod = -1;
416 r_shadow_shadowmapsize = 0;
417 r_shadow_shadowmapsampler = false;
418 r_shadow_shadowmappcf = 0;
419 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
420 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
422 switch(vid.renderpath)
424 case RENDERPATH_GL20:
425 if(r_shadow_shadowmapfilterquality < 0)
427 if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
428 r_shadow_shadowmappcf = 1;
429 else if(strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD"))
431 r_shadow_shadowmapsampler = vid.support.arb_shadow;
432 r_shadow_shadowmappcf = 1;
434 else if(strstr(gl_vendor, "ATI"))
435 r_shadow_shadowmappcf = 1;
437 r_shadow_shadowmapsampler = vid.support.arb_shadow;
441 switch (r_shadow_shadowmapfilterquality)
444 r_shadow_shadowmapsampler = vid.support.arb_shadow;
447 r_shadow_shadowmapsampler = vid.support.arb_shadow;
448 r_shadow_shadowmappcf = 1;
451 r_shadow_shadowmappcf = 1;
454 r_shadow_shadowmappcf = 2;
458 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
460 case RENDERPATH_D3D9:
461 case RENDERPATH_D3D10:
462 case RENDERPATH_D3D11:
463 case RENDERPATH_SOFT:
464 r_shadow_shadowmapsampler = false;
465 r_shadow_shadowmappcf = 1;
466 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
468 case RENDERPATH_GL13:
470 case RENDERPATH_GL11:
472 case RENDERPATH_GLES2:
478 qboolean R_Shadow_ShadowMappingEnabled(void)
480 switch (r_shadow_shadowmode)
482 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
489 void R_Shadow_FreeShadowMaps(void)
491 R_Shadow_SetShadowMode();
493 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
497 if (r_shadow_shadowmap2dtexture)
498 R_FreeTexture(r_shadow_shadowmap2dtexture);
499 r_shadow_shadowmap2dtexture = NULL;
501 if (r_shadow_shadowmap2dcolortexture)
502 R_FreeTexture(r_shadow_shadowmap2dcolortexture);
503 r_shadow_shadowmap2dcolortexture = NULL;
505 if (r_shadow_shadowmapvsdcttexture)
506 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
507 r_shadow_shadowmapvsdcttexture = NULL;
510 void r_shadow_start(void)
512 // allocate vertex processing arrays
513 r_shadow_bouncegridpixels = NULL;
514 r_shadow_bouncegridhighpixels = NULL;
515 r_shadow_bouncegridnumpixels = 0;
516 r_shadow_bouncegridtexture = NULL;
517 r_shadow_attenuationgradienttexture = NULL;
518 r_shadow_attenuation2dtexture = NULL;
519 r_shadow_attenuation3dtexture = NULL;
520 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
521 r_shadow_shadowmap2dtexture = NULL;
522 r_shadow_shadowmap2dcolortexture = NULL;
523 r_shadow_shadowmapvsdcttexture = NULL;
524 r_shadow_shadowmapmaxsize = 0;
525 r_shadow_shadowmapsize = 0;
526 r_shadow_shadowmaplod = 0;
527 r_shadow_shadowmapfilterquality = -1;
528 r_shadow_shadowmapdepthbits = 0;
529 r_shadow_shadowmapvsdct = false;
530 r_shadow_shadowmapsampler = false;
531 r_shadow_shadowmappcf = 0;
534 R_Shadow_FreeShadowMaps();
536 r_shadow_texturepool = NULL;
537 r_shadow_filters_texturepool = NULL;
538 R_Shadow_ValidateCvars();
539 R_Shadow_MakeTextures();
540 maxshadowtriangles = 0;
541 shadowelements = NULL;
542 maxshadowvertices = 0;
543 shadowvertex3f = NULL;
551 shadowmarklist = NULL;
556 shadowsideslist = NULL;
557 r_shadow_buffer_numleafpvsbytes = 0;
558 r_shadow_buffer_visitingleafpvs = NULL;
559 r_shadow_buffer_leafpvs = NULL;
560 r_shadow_buffer_leaflist = NULL;
561 r_shadow_buffer_numsurfacepvsbytes = 0;
562 r_shadow_buffer_surfacepvs = NULL;
563 r_shadow_buffer_surfacelist = NULL;
564 r_shadow_buffer_surfacesides = NULL;
565 r_shadow_buffer_numshadowtrispvsbytes = 0;
566 r_shadow_buffer_shadowtrispvs = NULL;
567 r_shadow_buffer_numlighttrispvsbytes = 0;
568 r_shadow_buffer_lighttrispvs = NULL;
570 r_shadow_usingdeferredprepass = false;
571 r_shadow_prepass_width = r_shadow_prepass_height = 0;
574 static void R_Shadow_FreeDeferred(void);
575 void r_shadow_shutdown(void)
578 R_Shadow_UncompileWorldLights();
580 R_Shadow_FreeShadowMaps();
582 r_shadow_usingdeferredprepass = false;
583 if (r_shadow_prepass_width)
584 R_Shadow_FreeDeferred();
585 r_shadow_prepass_width = r_shadow_prepass_height = 0;
588 r_shadow_bouncegridtexture = NULL;
589 r_shadow_bouncegridpixels = NULL;
590 r_shadow_bouncegridhighpixels = NULL;
591 r_shadow_bouncegridnumpixels = 0;
592 r_shadow_attenuationgradienttexture = NULL;
593 r_shadow_attenuation2dtexture = NULL;
594 r_shadow_attenuation3dtexture = NULL;
595 R_FreeTexturePool(&r_shadow_texturepool);
596 R_FreeTexturePool(&r_shadow_filters_texturepool);
597 maxshadowtriangles = 0;
599 Mem_Free(shadowelements);
600 shadowelements = NULL;
602 Mem_Free(shadowvertex3f);
603 shadowvertex3f = NULL;
606 Mem_Free(vertexupdate);
609 Mem_Free(vertexremap);
615 Mem_Free(shadowmark);
618 Mem_Free(shadowmarklist);
619 shadowmarklist = NULL;
624 Mem_Free(shadowsides);
627 Mem_Free(shadowsideslist);
628 shadowsideslist = NULL;
629 r_shadow_buffer_numleafpvsbytes = 0;
630 if (r_shadow_buffer_visitingleafpvs)
631 Mem_Free(r_shadow_buffer_visitingleafpvs);
632 r_shadow_buffer_visitingleafpvs = NULL;
633 if (r_shadow_buffer_leafpvs)
634 Mem_Free(r_shadow_buffer_leafpvs);
635 r_shadow_buffer_leafpvs = NULL;
636 if (r_shadow_buffer_leaflist)
637 Mem_Free(r_shadow_buffer_leaflist);
638 r_shadow_buffer_leaflist = NULL;
639 r_shadow_buffer_numsurfacepvsbytes = 0;
640 if (r_shadow_buffer_surfacepvs)
641 Mem_Free(r_shadow_buffer_surfacepvs);
642 r_shadow_buffer_surfacepvs = NULL;
643 if (r_shadow_buffer_surfacelist)
644 Mem_Free(r_shadow_buffer_surfacelist);
645 r_shadow_buffer_surfacelist = NULL;
646 if (r_shadow_buffer_surfacesides)
647 Mem_Free(r_shadow_buffer_surfacesides);
648 r_shadow_buffer_surfacesides = NULL;
649 r_shadow_buffer_numshadowtrispvsbytes = 0;
650 if (r_shadow_buffer_shadowtrispvs)
651 Mem_Free(r_shadow_buffer_shadowtrispvs);
652 r_shadow_buffer_numlighttrispvsbytes = 0;
653 if (r_shadow_buffer_lighttrispvs)
654 Mem_Free(r_shadow_buffer_lighttrispvs);
657 void r_shadow_newmap(void)
659 if (r_shadow_bouncegridtexture) R_FreeTexture(r_shadow_bouncegridtexture);r_shadow_bouncegridtexture = NULL;
660 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
661 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
662 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
663 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
664 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
665 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
666 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
667 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
668 R_Shadow_EditLights_Reload_f();
671 void R_Shadow_Init(void)
673 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
674 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
675 Cvar_RegisterVariable(&r_shadow_usebihculling);
676 Cvar_RegisterVariable(&r_shadow_usenormalmap);
677 Cvar_RegisterVariable(&r_shadow_debuglight);
678 Cvar_RegisterVariable(&r_shadow_deferred);
679 Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
680 // Cvar_RegisterVariable(&r_shadow_deferred_fp);
681 Cvar_RegisterVariable(&r_shadow_gloss);
682 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
683 Cvar_RegisterVariable(&r_shadow_glossintensity);
684 Cvar_RegisterVariable(&r_shadow_glossexponent);
685 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
686 Cvar_RegisterVariable(&r_shadow_glossexact);
687 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
688 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
689 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
690 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
691 Cvar_RegisterVariable(&r_shadow_projectdistance);
692 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
693 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
694 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
695 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
696 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
697 Cvar_RegisterVariable(&r_shadow_realtime_world);
698 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
699 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
700 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
701 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
702 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
703 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
704 Cvar_RegisterVariable(&r_shadow_scissor);
705 Cvar_RegisterVariable(&r_shadow_shadowmapping);
706 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
707 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
708 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
709 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
710 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
711 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
712 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
713 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
714 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
715 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
716 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
717 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
718 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
719 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
720 Cvar_RegisterVariable(&r_shadow_polygonfactor);
721 Cvar_RegisterVariable(&r_shadow_polygonoffset);
722 Cvar_RegisterVariable(&r_shadow_texture3d);
723 Cvar_RegisterVariable(&r_shadow_particletrace);
724 Cvar_RegisterVariable(&r_shadow_particletrace_intensity);
725 Cvar_RegisterVariable(&r_shadow_particletrace_size);
726 Cvar_RegisterVariable(&r_shadow_particletrace_radiusscale);
727 Cvar_RegisterVariable(&r_shadow_particletrace_maxbounce);
728 Cvar_RegisterVariable(&r_shadow_particletrace_bounceintensity);
729 Cvar_RegisterVariable(&r_shadow_particletrace_particlespacing);
730 Cvar_RegisterVariable(&r_shadow_particletrace_updatepercentage);
731 Cvar_RegisterVariable(&r_shadow_bouncegrid);
732 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
733 Cvar_RegisterVariable(&r_shadow_bouncegrid_dlightparticlemultiplier);
734 Cvar_RegisterVariable(&r_shadow_bouncegrid_hitmodels);
735 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
736 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightradiusscale);
737 Cvar_RegisterVariable(&r_shadow_bouncegrid_maxbounce);
738 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
739 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
740 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlespacing);
741 Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingx);
742 Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingy);
743 Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingz);
744 Cvar_RegisterVariable(&r_shadow_bouncegrid_stablerandom);
745 Cvar_RegisterVariable(&r_shadow_bouncegrid_updateinterval);
746 Cvar_RegisterVariable(&r_shadow_bouncegrid_x);
747 Cvar_RegisterVariable(&r_shadow_bouncegrid_y);
748 Cvar_RegisterVariable(&r_shadow_bouncegrid_z);
749 Cvar_RegisterVariable(&r_coronas);
750 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
751 Cvar_RegisterVariable(&r_coronas_occlusionquery);
752 Cvar_RegisterVariable(&gl_flashblend);
753 Cvar_RegisterVariable(&gl_ext_separatestencil);
754 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
755 R_Shadow_EditLights_Init();
756 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
757 maxshadowtriangles = 0;
758 shadowelements = NULL;
759 maxshadowvertices = 0;
760 shadowvertex3f = NULL;
768 shadowmarklist = NULL;
773 shadowsideslist = NULL;
774 r_shadow_buffer_numleafpvsbytes = 0;
775 r_shadow_buffer_visitingleafpvs = NULL;
776 r_shadow_buffer_leafpvs = NULL;
777 r_shadow_buffer_leaflist = NULL;
778 r_shadow_buffer_numsurfacepvsbytes = 0;
779 r_shadow_buffer_surfacepvs = NULL;
780 r_shadow_buffer_surfacelist = NULL;
781 r_shadow_buffer_surfacesides = NULL;
782 r_shadow_buffer_shadowtrispvs = NULL;
783 r_shadow_buffer_lighttrispvs = NULL;
784 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
787 matrix4x4_t matrix_attenuationxyz =
790 {0.5, 0.0, 0.0, 0.5},
791 {0.0, 0.5, 0.0, 0.5},
792 {0.0, 0.0, 0.5, 0.5},
797 matrix4x4_t matrix_attenuationz =
800 {0.0, 0.0, 0.5, 0.5},
801 {0.0, 0.0, 0.0, 0.5},
802 {0.0, 0.0, 0.0, 0.5},
807 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
809 numvertices = ((numvertices + 255) & ~255) * vertscale;
810 numtriangles = ((numtriangles + 255) & ~255) * triscale;
811 // make sure shadowelements is big enough for this volume
812 if (maxshadowtriangles < numtriangles)
814 maxshadowtriangles = numtriangles;
816 Mem_Free(shadowelements);
817 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
819 // make sure shadowvertex3f is big enough for this volume
820 if (maxshadowvertices < numvertices)
822 maxshadowvertices = numvertices;
824 Mem_Free(shadowvertex3f);
825 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
829 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
831 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
832 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
833 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
834 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
835 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
837 if (r_shadow_buffer_visitingleafpvs)
838 Mem_Free(r_shadow_buffer_visitingleafpvs);
839 if (r_shadow_buffer_leafpvs)
840 Mem_Free(r_shadow_buffer_leafpvs);
841 if (r_shadow_buffer_leaflist)
842 Mem_Free(r_shadow_buffer_leaflist);
843 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
844 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
845 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
846 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
848 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
850 if (r_shadow_buffer_surfacepvs)
851 Mem_Free(r_shadow_buffer_surfacepvs);
852 if (r_shadow_buffer_surfacelist)
853 Mem_Free(r_shadow_buffer_surfacelist);
854 if (r_shadow_buffer_surfacesides)
855 Mem_Free(r_shadow_buffer_surfacesides);
856 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
857 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
858 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
859 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
861 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
863 if (r_shadow_buffer_shadowtrispvs)
864 Mem_Free(r_shadow_buffer_shadowtrispvs);
865 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
866 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
868 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
870 if (r_shadow_buffer_lighttrispvs)
871 Mem_Free(r_shadow_buffer_lighttrispvs);
872 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
873 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
877 void R_Shadow_PrepareShadowMark(int numtris)
879 // make sure shadowmark is big enough for this volume
880 if (maxshadowmark < numtris)
882 maxshadowmark = numtris;
884 Mem_Free(shadowmark);
886 Mem_Free(shadowmarklist);
887 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
888 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
892 // if shadowmarkcount wrapped we clear the array and adjust accordingly
893 if (shadowmarkcount == 0)
896 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
901 void R_Shadow_PrepareShadowSides(int numtris)
903 if (maxshadowsides < numtris)
905 maxshadowsides = numtris;
907 Mem_Free(shadowsides);
909 Mem_Free(shadowsideslist);
910 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
911 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
916 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)
919 int outtriangles = 0, outvertices = 0;
922 float ratio, direction[3], projectvector[3];
924 if (projectdirection)
925 VectorScale(projectdirection, projectdistance, projectvector);
927 VectorClear(projectvector);
929 // create the vertices
930 if (projectdirection)
932 for (i = 0;i < numshadowmarktris;i++)
934 element = inelement3i + shadowmarktris[i] * 3;
935 for (j = 0;j < 3;j++)
937 if (vertexupdate[element[j]] != vertexupdatenum)
939 vertexupdate[element[j]] = vertexupdatenum;
940 vertexremap[element[j]] = outvertices;
941 vertex = invertex3f + element[j] * 3;
942 // project one copy of the vertex according to projectvector
943 VectorCopy(vertex, outvertex3f);
944 VectorAdd(vertex, projectvector, (outvertex3f + 3));
953 for (i = 0;i < numshadowmarktris;i++)
955 element = inelement3i + shadowmarktris[i] * 3;
956 for (j = 0;j < 3;j++)
958 if (vertexupdate[element[j]] != vertexupdatenum)
960 vertexupdate[element[j]] = vertexupdatenum;
961 vertexremap[element[j]] = outvertices;
962 vertex = invertex3f + element[j] * 3;
963 // project one copy of the vertex to the sphere radius of the light
964 // (FIXME: would projecting it to the light box be better?)
965 VectorSubtract(vertex, projectorigin, direction);
966 ratio = projectdistance / VectorLength(direction);
967 VectorCopy(vertex, outvertex3f);
968 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
976 if (r_shadow_frontsidecasting.integer)
978 for (i = 0;i < numshadowmarktris;i++)
980 int remappedelement[3];
982 const int *neighbortriangle;
984 markindex = shadowmarktris[i] * 3;
985 element = inelement3i + markindex;
986 neighbortriangle = inneighbor3i + markindex;
987 // output the front and back triangles
988 outelement3i[0] = vertexremap[element[0]];
989 outelement3i[1] = vertexremap[element[1]];
990 outelement3i[2] = vertexremap[element[2]];
991 outelement3i[3] = vertexremap[element[2]] + 1;
992 outelement3i[4] = vertexremap[element[1]] + 1;
993 outelement3i[5] = vertexremap[element[0]] + 1;
997 // output the sides (facing outward from this triangle)
998 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1000 remappedelement[0] = vertexremap[element[0]];
1001 remappedelement[1] = vertexremap[element[1]];
1002 outelement3i[0] = remappedelement[1];
1003 outelement3i[1] = remappedelement[0];
1004 outelement3i[2] = remappedelement[0] + 1;
1005 outelement3i[3] = remappedelement[1];
1006 outelement3i[4] = remappedelement[0] + 1;
1007 outelement3i[5] = remappedelement[1] + 1;
1012 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1014 remappedelement[1] = vertexremap[element[1]];
1015 remappedelement[2] = vertexremap[element[2]];
1016 outelement3i[0] = remappedelement[2];
1017 outelement3i[1] = remappedelement[1];
1018 outelement3i[2] = remappedelement[1] + 1;
1019 outelement3i[3] = remappedelement[2];
1020 outelement3i[4] = remappedelement[1] + 1;
1021 outelement3i[5] = remappedelement[2] + 1;
1026 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1028 remappedelement[0] = vertexremap[element[0]];
1029 remappedelement[2] = vertexremap[element[2]];
1030 outelement3i[0] = remappedelement[0];
1031 outelement3i[1] = remappedelement[2];
1032 outelement3i[2] = remappedelement[2] + 1;
1033 outelement3i[3] = remappedelement[0];
1034 outelement3i[4] = remappedelement[2] + 1;
1035 outelement3i[5] = remappedelement[0] + 1;
1044 for (i = 0;i < numshadowmarktris;i++)
1046 int remappedelement[3];
1048 const int *neighbortriangle;
1050 markindex = shadowmarktris[i] * 3;
1051 element = inelement3i + markindex;
1052 neighbortriangle = inneighbor3i + markindex;
1053 // output the front and back triangles
1054 outelement3i[0] = vertexremap[element[2]];
1055 outelement3i[1] = vertexremap[element[1]];
1056 outelement3i[2] = vertexremap[element[0]];
1057 outelement3i[3] = vertexremap[element[0]] + 1;
1058 outelement3i[4] = vertexremap[element[1]] + 1;
1059 outelement3i[5] = vertexremap[element[2]] + 1;
1063 // output the sides (facing outward from this triangle)
1064 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1066 remappedelement[0] = vertexremap[element[0]];
1067 remappedelement[1] = vertexremap[element[1]];
1068 outelement3i[0] = remappedelement[0];
1069 outelement3i[1] = remappedelement[1];
1070 outelement3i[2] = remappedelement[1] + 1;
1071 outelement3i[3] = remappedelement[0];
1072 outelement3i[4] = remappedelement[1] + 1;
1073 outelement3i[5] = remappedelement[0] + 1;
1078 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1080 remappedelement[1] = vertexremap[element[1]];
1081 remappedelement[2] = vertexremap[element[2]];
1082 outelement3i[0] = remappedelement[1];
1083 outelement3i[1] = remappedelement[2];
1084 outelement3i[2] = remappedelement[2] + 1;
1085 outelement3i[3] = remappedelement[1];
1086 outelement3i[4] = remappedelement[2] + 1;
1087 outelement3i[5] = remappedelement[1] + 1;
1092 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1094 remappedelement[0] = vertexremap[element[0]];
1095 remappedelement[2] = vertexremap[element[2]];
1096 outelement3i[0] = remappedelement[2];
1097 outelement3i[1] = remappedelement[0];
1098 outelement3i[2] = remappedelement[0] + 1;
1099 outelement3i[3] = remappedelement[2];
1100 outelement3i[4] = remappedelement[0] + 1;
1101 outelement3i[5] = remappedelement[2] + 1;
1109 *outnumvertices = outvertices;
1110 return outtriangles;
1113 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)
1116 int outtriangles = 0, outvertices = 0;
1118 const float *vertex;
1119 float ratio, direction[3], projectvector[3];
1122 if (projectdirection)
1123 VectorScale(projectdirection, projectdistance, projectvector);
1125 VectorClear(projectvector);
1127 for (i = 0;i < numshadowmarktris;i++)
1129 int remappedelement[3];
1131 const int *neighbortriangle;
1133 markindex = shadowmarktris[i] * 3;
1134 neighbortriangle = inneighbor3i + markindex;
1135 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1136 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1137 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1138 if (side[0] + side[1] + side[2] == 0)
1142 element = inelement3i + markindex;
1144 // create the vertices
1145 for (j = 0;j < 3;j++)
1147 if (side[j] + side[j+1] == 0)
1150 if (vertexupdate[k] != vertexupdatenum)
1152 vertexupdate[k] = vertexupdatenum;
1153 vertexremap[k] = outvertices;
1154 vertex = invertex3f + k * 3;
1155 VectorCopy(vertex, outvertex3f);
1156 if (projectdirection)
1158 // project one copy of the vertex according to projectvector
1159 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1163 // project one copy of the vertex to the sphere radius of the light
1164 // (FIXME: would projecting it to the light box be better?)
1165 VectorSubtract(vertex, projectorigin, direction);
1166 ratio = projectdistance / VectorLength(direction);
1167 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1174 // output the sides (facing outward from this triangle)
1177 remappedelement[0] = vertexremap[element[0]];
1178 remappedelement[1] = vertexremap[element[1]];
1179 outelement3i[0] = remappedelement[1];
1180 outelement3i[1] = remappedelement[0];
1181 outelement3i[2] = remappedelement[0] + 1;
1182 outelement3i[3] = remappedelement[1];
1183 outelement3i[4] = remappedelement[0] + 1;
1184 outelement3i[5] = remappedelement[1] + 1;
1191 remappedelement[1] = vertexremap[element[1]];
1192 remappedelement[2] = vertexremap[element[2]];
1193 outelement3i[0] = remappedelement[2];
1194 outelement3i[1] = remappedelement[1];
1195 outelement3i[2] = remappedelement[1] + 1;
1196 outelement3i[3] = remappedelement[2];
1197 outelement3i[4] = remappedelement[1] + 1;
1198 outelement3i[5] = remappedelement[2] + 1;
1205 remappedelement[0] = vertexremap[element[0]];
1206 remappedelement[2] = vertexremap[element[2]];
1207 outelement3i[0] = remappedelement[0];
1208 outelement3i[1] = remappedelement[2];
1209 outelement3i[2] = remappedelement[2] + 1;
1210 outelement3i[3] = remappedelement[0];
1211 outelement3i[4] = remappedelement[2] + 1;
1212 outelement3i[5] = remappedelement[0] + 1;
1219 *outnumvertices = outvertices;
1220 return outtriangles;
1223 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)
1229 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1231 tend = firsttriangle + numtris;
1232 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1234 // surface box entirely inside light box, no box cull
1235 if (projectdirection)
1237 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1239 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1240 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1241 shadowmarklist[numshadowmark++] = t;
1246 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1247 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1248 shadowmarklist[numshadowmark++] = t;
1253 // surface box not entirely inside light box, cull each triangle
1254 if (projectdirection)
1256 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1258 v[0] = invertex3f + e[0] * 3;
1259 v[1] = invertex3f + e[1] * 3;
1260 v[2] = invertex3f + e[2] * 3;
1261 TriangleNormal(v[0], v[1], v[2], normal);
1262 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1263 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1264 shadowmarklist[numshadowmark++] = t;
1269 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1271 v[0] = invertex3f + e[0] * 3;
1272 v[1] = invertex3f + e[1] * 3;
1273 v[2] = invertex3f + e[2] * 3;
1274 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1275 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1276 shadowmarklist[numshadowmark++] = t;
1282 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1287 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1289 // check if the shadow volume intersects the near plane
1291 // a ray between the eye and light origin may intersect the caster,
1292 // indicating that the shadow may touch the eye location, however we must
1293 // test the near plane (a polygon), not merely the eye location, so it is
1294 // easiest to enlarge the caster bounding shape slightly for this.
1300 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)
1302 int i, tris, outverts;
1303 if (projectdistance < 0.1)
1305 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1308 if (!numverts || !nummarktris)
1310 // make sure shadowelements is big enough for this volume
1311 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1312 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1314 if (maxvertexupdate < numverts)
1316 maxvertexupdate = numverts;
1318 Mem_Free(vertexupdate);
1320 Mem_Free(vertexremap);
1321 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1322 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1323 vertexupdatenum = 0;
1326 if (vertexupdatenum == 0)
1328 vertexupdatenum = 1;
1329 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1330 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1333 for (i = 0;i < nummarktris;i++)
1334 shadowmark[marktris[i]] = shadowmarkcount;
1336 if (r_shadow_compilingrtlight)
1338 // if we're compiling an rtlight, capture the mesh
1339 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1340 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1341 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1342 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1344 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1346 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1347 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1348 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1352 // decide which type of shadow to generate and set stencil mode
1353 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1354 // generate the sides or a solid volume, depending on type
1355 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1356 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1358 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1359 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1360 r_refdef.stats.lights_shadowtriangles += tris;
1361 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1363 // increment stencil if frontface is infront of depthbuffer
1364 GL_CullFace(r_refdef.view.cullface_front);
1365 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1366 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1367 // decrement stencil if backface is infront of depthbuffer
1368 GL_CullFace(r_refdef.view.cullface_back);
1369 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1371 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1373 // decrement stencil if backface is behind depthbuffer
1374 GL_CullFace(r_refdef.view.cullface_front);
1375 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1376 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1377 // increment stencil if frontface is behind depthbuffer
1378 GL_CullFace(r_refdef.view.cullface_back);
1379 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1381 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1382 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1386 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1388 // p1, p2, p3 are in the cubemap's local coordinate system
1389 // bias = border/(size - border)
1392 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1393 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1394 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1395 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1397 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1398 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1399 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1400 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1402 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1403 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1404 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1406 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1407 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1408 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1409 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1411 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1412 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1413 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1414 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1416 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1417 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1418 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1420 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1421 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1422 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1423 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1425 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1426 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1427 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1428 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1430 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1431 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1432 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1437 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1439 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1440 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1443 VectorSubtract(maxs, mins, radius);
1444 VectorScale(radius, 0.5f, radius);
1445 VectorAdd(mins, radius, center);
1446 Matrix4x4_Transform(worldtolight, center, lightcenter);
1447 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1448 VectorSubtract(lightcenter, lightradius, pmin);
1449 VectorAdd(lightcenter, lightradius, pmax);
1451 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1452 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1453 if(ap1 > bias*an1 && ap2 > bias*an2)
1455 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1456 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1457 if(an1 > bias*ap1 && an2 > bias*ap2)
1459 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1460 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1462 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1463 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1464 if(ap1 > bias*an1 && ap2 > bias*an2)
1466 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1467 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1468 if(an1 > bias*ap1 && an2 > bias*ap2)
1470 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1471 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1473 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1474 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1475 if(ap1 > bias*an1 && ap2 > bias*an2)
1477 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1478 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1479 if(an1 > bias*ap1 && an2 > bias*ap2)
1481 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1482 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1487 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1489 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1491 // p is in the cubemap's local coordinate system
1492 // bias = border/(size - border)
1493 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1494 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1495 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1497 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1498 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1499 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1500 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1501 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1502 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1506 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1510 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1511 float scale = (size - 2*border)/size, len;
1512 float bias = border / (float)(size - border), dp, dn, ap, an;
1513 // check if cone enclosing side would cross frustum plane
1514 scale = 2 / (scale*scale + 2);
1515 for (i = 0;i < 5;i++)
1517 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1519 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1520 len = scale*VectorLength2(n);
1521 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1522 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1523 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1525 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1527 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1528 len = scale*VectorLength(n);
1529 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1530 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1531 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1533 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1534 // check if frustum corners/origin cross plane sides
1536 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1537 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1538 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1539 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1540 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1541 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1542 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1543 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1544 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1545 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1546 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1547 for (i = 0;i < 4;i++)
1549 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1550 VectorSubtract(n, p, n);
1551 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1552 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1553 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1554 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1555 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1556 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1557 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1558 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1559 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1562 // finite version, assumes corners are a finite distance from origin dependent on far plane
1563 for (i = 0;i < 5;i++)
1565 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1566 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1567 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1568 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1569 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1570 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1571 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1572 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1573 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1574 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1577 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1580 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)
1588 int mask, surfacemask = 0;
1589 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1591 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1592 tend = firsttriangle + numtris;
1593 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1595 // surface box entirely inside light box, no box cull
1596 if (projectdirection)
1598 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1600 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1601 TriangleNormal(v[0], v[1], v[2], normal);
1602 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1604 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1605 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1606 surfacemask |= mask;
1609 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;
1610 shadowsides[numshadowsides] = mask;
1611 shadowsideslist[numshadowsides++] = t;
1618 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1620 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1621 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1623 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1624 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1625 surfacemask |= mask;
1628 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;
1629 shadowsides[numshadowsides] = mask;
1630 shadowsideslist[numshadowsides++] = t;
1638 // surface box not entirely inside light box, cull each triangle
1639 if (projectdirection)
1641 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1643 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1644 TriangleNormal(v[0], v[1], v[2], normal);
1645 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1646 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1648 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1649 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1650 surfacemask |= mask;
1653 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;
1654 shadowsides[numshadowsides] = mask;
1655 shadowsideslist[numshadowsides++] = t;
1662 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1664 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1665 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1666 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1668 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1669 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1670 surfacemask |= mask;
1673 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;
1674 shadowsides[numshadowsides] = mask;
1675 shadowsideslist[numshadowsides++] = t;
1684 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)
1686 int i, j, outtriangles = 0;
1687 int *outelement3i[6];
1688 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1690 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1691 // make sure shadowelements is big enough for this mesh
1692 if (maxshadowtriangles < outtriangles)
1693 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1695 // compute the offset and size of the separate index lists for each cubemap side
1697 for (i = 0;i < 6;i++)
1699 outelement3i[i] = shadowelements + outtriangles * 3;
1700 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1701 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1702 outtriangles += sidetotals[i];
1705 // gather up the (sparse) triangles into separate index lists for each cubemap side
1706 for (i = 0;i < numsidetris;i++)
1708 const int *element = elements + sidetris[i] * 3;
1709 for (j = 0;j < 6;j++)
1711 if (sides[i] & (1 << j))
1713 outelement3i[j][0] = element[0];
1714 outelement3i[j][1] = element[1];
1715 outelement3i[j][2] = element[2];
1716 outelement3i[j] += 3;
1721 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1724 static void R_Shadow_MakeTextures_MakeCorona(void)
1728 unsigned char pixels[32][32][4];
1729 for (y = 0;y < 32;y++)
1731 dy = (y - 15.5f) * (1.0f / 16.0f);
1732 for (x = 0;x < 32;x++)
1734 dx = (x - 15.5f) * (1.0f / 16.0f);
1735 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1736 a = bound(0, a, 255);
1737 pixels[y][x][0] = a;
1738 pixels[y][x][1] = a;
1739 pixels[y][x][2] = a;
1740 pixels[y][x][3] = 255;
1743 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1746 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1748 float dist = sqrt(x*x+y*y+z*z);
1749 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1750 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1751 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1754 static void R_Shadow_MakeTextures(void)
1757 float intensity, dist;
1759 R_Shadow_FreeShadowMaps();
1760 R_FreeTexturePool(&r_shadow_texturepool);
1761 r_shadow_texturepool = R_AllocTexturePool();
1762 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1763 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1764 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1765 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1766 for (x = 0;x <= ATTENTABLESIZE;x++)
1768 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1769 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1770 r_shadow_attentable[x] = bound(0, intensity, 1);
1772 // 1D gradient texture
1773 for (x = 0;x < ATTEN1DSIZE;x++)
1774 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1775 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1776 // 2D circle texture
1777 for (y = 0;y < ATTEN2DSIZE;y++)
1778 for (x = 0;x < ATTEN2DSIZE;x++)
1779 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);
1780 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1781 // 3D sphere texture
1782 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1784 for (z = 0;z < ATTEN3DSIZE;z++)
1785 for (y = 0;y < ATTEN3DSIZE;y++)
1786 for (x = 0;x < ATTEN3DSIZE;x++)
1787 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));
1788 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);
1791 r_shadow_attenuation3dtexture = NULL;
1794 R_Shadow_MakeTextures_MakeCorona();
1796 // Editor light sprites
1797 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1814 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1815 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1832 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1833 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1850 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1851 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1868 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1869 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1886 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1887 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1904 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1907 void R_Shadow_ValidateCvars(void)
1909 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1910 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1911 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1912 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1913 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1914 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1917 void R_Shadow_RenderMode_Begin(void)
1923 R_Shadow_ValidateCvars();
1925 if (!r_shadow_attenuation2dtexture
1926 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1927 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1928 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1929 R_Shadow_MakeTextures();
1932 R_Mesh_ResetTextureState();
1933 GL_BlendFunc(GL_ONE, GL_ZERO);
1934 GL_DepthRange(0, 1);
1935 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1937 GL_DepthMask(false);
1938 GL_Color(0, 0, 0, 1);
1939 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1941 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1943 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1945 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1946 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1948 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1950 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1951 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1955 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1956 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1959 switch(vid.renderpath)
1961 case RENDERPATH_GL20:
1962 case RENDERPATH_D3D9:
1963 case RENDERPATH_D3D10:
1964 case RENDERPATH_D3D11:
1965 case RENDERPATH_SOFT:
1966 case RENDERPATH_GLES2:
1967 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1969 case RENDERPATH_GL13:
1970 case RENDERPATH_GL11:
1971 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1972 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1973 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1974 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1975 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1976 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1978 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1984 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1985 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1986 r_shadow_drawbuffer = drawbuffer;
1987 r_shadow_readbuffer = readbuffer;
1989 r_shadow_cullface_front = r_refdef.view.cullface_front;
1990 r_shadow_cullface_back = r_refdef.view.cullface_back;
1993 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1995 rsurface.rtlight = rtlight;
1998 void R_Shadow_RenderMode_Reset(void)
2000 R_Mesh_ResetRenderTargets();
2001 R_SetViewport(&r_refdef.view.viewport);
2002 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
2003 R_Mesh_ResetTextureState();
2004 GL_DepthRange(0, 1);
2006 GL_DepthMask(false);
2007 GL_DepthFunc(GL_LEQUAL);
2008 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2009 r_refdef.view.cullface_front = r_shadow_cullface_front;
2010 r_refdef.view.cullface_back = r_shadow_cullface_back;
2011 GL_CullFace(r_refdef.view.cullface_back);
2012 GL_Color(1, 1, 1, 1);
2013 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2014 GL_BlendFunc(GL_ONE, GL_ZERO);
2015 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
2016 r_shadow_usingshadowmap2d = false;
2017 r_shadow_usingshadowmaportho = false;
2018 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2021 void R_Shadow_ClearStencil(void)
2023 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2024 r_refdef.stats.lights_clears++;
2027 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2029 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2030 if (r_shadow_rendermode == mode)
2032 R_Shadow_RenderMode_Reset();
2033 GL_DepthFunc(GL_LESS);
2034 GL_ColorMask(0, 0, 0, 0);
2035 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2036 GL_CullFace(GL_NONE);
2037 R_SetupShader_DepthOrShadow();
2038 r_shadow_rendermode = mode;
2043 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2044 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2045 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2047 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2048 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2049 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2054 static void R_Shadow_MakeVSDCT(void)
2056 // maps to a 2x3 texture rectangle with normalized coordinates
2061 // stores abs(dir.xy), offset.xy/2.5
2062 unsigned char data[4*6] =
2064 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2065 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2066 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2067 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2068 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2069 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2071 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2074 static void R_Shadow_MakeShadowMap(int side, int size)
2076 switch (r_shadow_shadowmode)
2078 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2079 if (r_shadow_shadowmap2dtexture) return;
2080 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);
2081 r_shadow_shadowmap2dcolortexture = NULL;
2082 switch(vid.renderpath)
2085 case RENDERPATH_D3D9:
2086 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);
2087 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2091 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, NULL, NULL, NULL, NULL);
2099 // render depth into the fbo, do not render color at all
2100 // validate the fbo now
2104 qglDrawBuffer(GL_NONE);CHECKGLERROR
2105 qglReadBuffer(GL_NONE);CHECKGLERROR
2106 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2107 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2109 Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2110 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2111 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2116 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2118 float nearclip, farclip, bias;
2119 r_viewport_t viewport;
2122 float clearcolor[4];
2123 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2125 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2126 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2127 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2128 r_shadow_shadowmapside = side;
2129 r_shadow_shadowmapsize = size;
2131 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2132 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2133 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2134 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2136 // complex unrolled cube approach (more flexible)
2137 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2138 R_Shadow_MakeVSDCT();
2139 if (!r_shadow_shadowmap2dtexture)
2140 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2141 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2142 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2143 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2144 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2146 R_Mesh_ResetTextureState();
2147 R_Mesh_ResetRenderTargets();
2148 R_Shadow_RenderMode_Reset();
2151 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2152 R_SetupShader_DepthOrShadow();
2155 R_SetupShader_ShowDepth();
2156 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2161 R_SetViewport(&viewport);
2162 flipped = (side & 1) ^ (side >> 2);
2163 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2164 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2165 switch(vid.renderpath)
2167 case RENDERPATH_GL11:
2168 case RENDERPATH_GL13:
2169 case RENDERPATH_GL20:
2170 case RENDERPATH_SOFT:
2171 case RENDERPATH_GLES2:
2172 GL_CullFace(r_refdef.view.cullface_back);
2173 // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
2174 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2176 // get tightest scissor rectangle that encloses all viewports in the clear mask
2177 int x1 = clear & 0x15 ? 0 : size;
2178 int x2 = clear & 0x2A ? 2 * size : size;
2179 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2180 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2181 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2182 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2184 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2186 case RENDERPATH_D3D9:
2187 case RENDERPATH_D3D10:
2188 case RENDERPATH_D3D11:
2189 Vector4Set(clearcolor, 1,1,1,1);
2190 // completely different meaning than in OpenGL path
2191 r_shadow_shadowmap_parameters[1] = 0;
2192 r_shadow_shadowmap_parameters[3] = -bias;
2193 // we invert the cull mode because we flip the projection matrix
2194 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2195 GL_CullFace(r_refdef.view.cullface_front);
2196 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2197 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2198 if (r_shadow_shadowmapsampler)
2200 GL_ColorMask(0,0,0,0);
2202 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2206 GL_ColorMask(1,1,1,1);
2208 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2214 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2216 R_Mesh_ResetTextureState();
2217 R_Mesh_ResetRenderTargets();
2220 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2221 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2222 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2223 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2225 R_Shadow_RenderMode_Reset();
2226 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2228 GL_DepthFunc(GL_EQUAL);
2229 // do global setup needed for the chosen lighting mode
2230 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2231 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2232 r_shadow_usingshadowmap2d = shadowmapping;
2233 r_shadow_rendermode = r_shadow_lightingrendermode;
2234 // only draw light where this geometry was already rendered AND the
2235 // stencil is 128 (values other than this mean shadow)
2237 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2239 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2242 static const unsigned short bboxelements[36] =
2252 static const float bboxpoints[8][3] =
2264 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2267 float vertex3f[8*3];
2268 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2269 // do global setup needed for the chosen lighting mode
2270 R_Shadow_RenderMode_Reset();
2271 r_shadow_rendermode = r_shadow_lightingrendermode;
2272 R_EntityMatrix(&identitymatrix);
2273 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2274 // only draw light where this geometry was already rendered AND the
2275 // stencil is 128 (values other than this mean shadow)
2276 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2277 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2279 r_shadow_usingshadowmap2d = shadowmapping;
2281 // render the lighting
2282 R_SetupShader_DeferredLight(rsurface.rtlight);
2283 for (i = 0;i < 8;i++)
2284 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2285 GL_ColorMask(1,1,1,1);
2286 GL_DepthMask(false);
2287 GL_DepthRange(0, 1);
2288 GL_PolygonOffset(0, 0);
2290 GL_DepthFunc(GL_GREATER);
2291 GL_CullFace(r_refdef.view.cullface_back);
2292 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL);
2293 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2296 static void R_Shadow_UpdateBounceGridTexture(void)
2298 #define MAXBOUNCEGRIDPARTICLESPERLIGHT 1048576
2300 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2303 int hitsupercontentsmask;
2312 unsigned char *pixel;
2313 unsigned char *pixels;
2314 unsigned short *highpixel;
2315 unsigned short *highpixels;
2316 unsigned int lightindex;
2318 unsigned int range1;
2319 unsigned int range2;
2320 unsigned int seed = (unsigned int)(realtime * 1000.0f);
2322 vec3_t baseshotcolor;
2334 vec_t lightintensity;
2336 qboolean isstatic = r_shadow_bouncegrid_updateinterval.value > 1.0f;
2338 if (!r_shadow_bouncegrid.integer || !vid.support.ext_texture_3d)
2340 if (r_shadow_bouncegridtexture)
2342 R_FreeTexture(r_shadow_bouncegridtexture);
2343 r_shadow_bouncegridtexture = NULL;
2345 if (r_shadow_bouncegridpixels)
2346 Mem_Free(r_shadow_bouncegridpixels);
2347 r_shadow_bouncegridpixels = NULL;
2348 if (r_shadow_bouncegridhighpixels)
2349 Mem_Free(r_shadow_bouncegridhighpixels);
2350 r_shadow_bouncegridhighpixels = NULL;
2351 r_shadow_bouncegridnumpixels = 0;
2354 if (r_refdef.scene.worldmodel && isstatic)
2356 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));
2357 VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
2358 VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
2359 VectorSubtract(maxs, mins, size);
2360 resolution[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2361 resolution[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2362 resolution[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2363 resolution[0] = min(resolution[0], bound(4, r_shadow_bouncegrid_x.integer, (int)vid.maxtexturesize_3d));
2364 resolution[1] = min(resolution[1], bound(4, r_shadow_bouncegrid_y.integer, (int)vid.maxtexturesize_3d));
2365 resolution[2] = min(resolution[2], bound(4, r_shadow_bouncegrid_z.integer, (int)vid.maxtexturesize_3d));
2366 spacing[0] = size[0] / resolution[0];
2367 spacing[1] = size[1] / resolution[1];
2368 spacing[2] = size[2] / resolution[2];
2369 ispacing[0] = 1.0f / spacing[0];
2370 ispacing[1] = 1.0f / spacing[1];
2371 ispacing[2] = 1.0f / spacing[2];
2375 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));
2376 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));
2377 VectorMultiply(resolution, spacing, size);
2378 ispacing[0] = 1.0f / spacing[0];
2379 ispacing[1] = 1.0f / spacing[1];
2380 ispacing[2] = 1.0f / spacing[2];
2381 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2382 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2383 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2384 VectorAdd(mins, size, maxs);
2386 r_shadow_bouncegridintensity = r_shadow_bouncegrid_intensity.value;
2387 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])
2389 // we're going to update the bouncegrid, update the matrix...
2390 memset(m, 0, sizeof(m));
2391 m[0] = 1.0f / size[0];
2392 m[3] = -mins[0] * m[0];
2393 m[5] = 1.0f / size[1];
2394 m[7] = -mins[1] * m[5];
2395 m[10] = 1.0f / size[2];
2396 m[11] = -mins[2] * m[10];
2398 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegridmatrix, m);
2399 numpixels = resolution[0]*resolution[1]*resolution[2];
2400 // reallocate pixels for this update if needed...
2401 if (r_shadow_bouncegridnumpixels != numpixels || !r_shadow_bouncegridpixels || !r_shadow_bouncegridhighpixels)
2403 r_shadow_bouncegridpixels = (unsigned char *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridpixels, numpixels * sizeof(unsigned char[4]));
2404 r_shadow_bouncegridhighpixels = (unsigned short *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridhighpixels, numpixels * sizeof(unsigned short[4]));
2406 r_shadow_bouncegridnumpixels = numpixels;
2407 pixels = r_shadow_bouncegridpixels;
2408 highpixels = r_shadow_bouncegridhighpixels;
2409 memset(pixels, 0, numpixels * sizeof(unsigned char[4]));
2410 memset(highpixels, 0, numpixels * sizeof(unsigned short[3]));
2411 // figure out what we want to interact with
2412 if (r_shadow_bouncegrid_hitmodels.integer)
2413 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK;
2415 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
2416 maxbounce = bound(1, r_shadow_bouncegrid_maxbounce.integer, 16);
2417 // iterate world rtlights
2418 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2419 range1 = isstatic ? 0 : r_refdef.scene.numlights;
2420 range2 = range + range1;
2421 for (lightindex = 0;lightindex < range2;lightindex++)
2425 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2426 if (!light || !(light->flags & flag))
2428 rtlight = &light->rtlight;
2429 // when static, we skip styled lights because they tend to change...
2430 if (rtlight->style > 0)
2432 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) * (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1), lightcolor);
2436 if (lightindex < range)
2438 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2439 rtlight = &light->rtlight;
2442 rtlight = r_refdef.scene.lights[lightindex - range];
2443 // draw only visible lights (major speedup)
2446 VectorScale(rtlight->currentcolor, rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale, lightcolor);
2448 if (!VectorLength2(lightcolor))
2450 // shoot particles from this light
2451 // use a calculation for the number of particles that will not
2452 // vary with lightstyle, otherwise we get randomized particle
2453 // distribution, the seeded random is only consistent for a
2454 // consistent number of particles on this light...
2455 radius = rtlight->radius * bound(0.0001f, r_shadow_bouncegrid_lightradiusscale.value, 1024.0f);
2456 s = rtlight->radius / bound(1.0f, r_shadow_bouncegrid_particlespacing.value, 1048576.0f);
2457 lightintensity = VectorLength(rtlight->color) * rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale;
2458 if (lightindex >= range)
2459 lightintensity *= r_shadow_bouncegrid_dlightparticlemultiplier.value;
2460 shootparticles = (int)bound(0, lightintensity * s *s, MAXBOUNCEGRIDPARTICLESPERLIGHT);
2461 if (!shootparticles)
2463 s = 65535.0f * r_shadow_bouncegrid_particleintensity.value / shootparticles;
2464 VectorScale(lightcolor, s, baseshotcolor);
2465 if (VectorLength2(baseshotcolor) < 3.0f)
2467 r_refdef.stats.bouncegrid_lights++;
2468 r_refdef.stats.bouncegrid_particles += shootparticles;
2469 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2471 if (r_shadow_bouncegrid_stablerandom.integer > 0)
2472 seed = lightindex * 11937 + shotparticles;
2473 VectorCopy(baseshotcolor, shotcolor);
2474 VectorCopy(rtlight->shadoworigin, clipstart);
2475 if (r_shadow_bouncegrid_stablerandom.integer < 0)
2476 VectorRandom(clipend);
2478 VectorCheeseRandom(clipend);
2479 VectorMA(clipstart, radius, clipend, clipend);
2480 for (bouncecount = 0;;bouncecount++)
2482 r_refdef.stats.bouncegrid_traces++;
2483 cliptrace = CL_TraceLine(clipstart, clipend, r_shadow_bouncegrid_hitmodels.integer ? MOVE_HITMODEL : MOVE_NOMONSTERS, NULL, hitsupercontentsmask, true, false, NULL, true);
2484 //Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask);
2485 if (cliptrace.fraction >= 1.0f)
2487 r_refdef.stats.bouncegrid_hits++;
2488 if (bouncecount > 0)
2490 r_refdef.stats.bouncegrid_splats++;
2491 // figure out which texture pixel this is in
2492 tex[0] = (int)((cliptrace.endpos[0] - mins[0]) * ispacing[0]);
2493 tex[1] = (int)((cliptrace.endpos[1] - mins[1]) * ispacing[1]);
2494 tex[2] = (int)((cliptrace.endpos[2] - mins[2]) * ispacing[2]);
2495 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)
2497 // it is within bounds...
2498 pixelindex = ((tex[2]*resolution[1]+tex[1])*resolution[0]+tex[0]);
2499 pixel = pixels + 4 * pixelindex;
2500 highpixel = highpixels + 3 * pixelindex;
2501 // add to the high precision pixel color
2502 c[0] = highpixel[0] + (int)shotcolor[2];
2503 c[1] = highpixel[1] + (int)shotcolor[1];
2504 c[2] = highpixel[2] + (int)shotcolor[0];
2505 highpixel[0] = (unsigned short)min(c[0], 65535);
2506 highpixel[1] = (unsigned short)min(c[1], 65535);
2507 highpixel[2] = (unsigned short)min(c[2], 65535);
2508 // update the low precision pixel color
2509 pixel[0] = highpixel[0] >> 8;
2510 pixel[1] = highpixel[1] >> 8;
2511 pixel[2] = highpixel[2] >> 8;
2515 if (bouncecount >= maxbounce)
2517 // scale down shot color by bounce intensity and texture color
2518 VectorScale(shotcolor, r_shadow_bouncegrid_particlebounceintensity.value, shotcolor);
2519 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2520 VectorMultiply(shotcolor, rsurface.texture->currentskinframe->avgcolor, shotcolor);
2521 if (VectorLength2(shotcolor) < 3.0f)
2523 r_refdef.stats.bouncegrid_bounces++;
2524 if (r_shadow_bouncegrid_bounceanglediffuse.integer)
2526 // random direction, primarily along plane normal
2527 s = VectorDistance(cliptrace.endpos, clipend);
2528 if (r_shadow_bouncegrid_stablerandom.integer < 0)
2529 VectorRandom(clipend);
2531 VectorCheeseRandom(clipend);
2532 VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
2533 VectorNormalize(clipend);
2534 VectorScale(clipend, s, clipend);
2538 // reflect the remaining portion of the line across plane normal
2539 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2540 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2542 // calculate the new line start and end
2543 VectorCopy(cliptrace.endpos, clipstart);
2544 VectorAdd(clipstart, clipend, clipend);
2548 if (r_shadow_bouncegridtexture && r_shadow_bouncegridresolution[0] == resolution[0] && r_shadow_bouncegridresolution[1] == resolution[1] && r_shadow_bouncegridresolution[2] == resolution[2])
2549 R_UpdateTexture(r_shadow_bouncegridtexture, pixels, 0, 0, 0, resolution[0], resolution[1], resolution[2]);
2552 VectorCopy(resolution, r_shadow_bouncegridresolution);
2553 if (r_shadow_bouncegridtexture)
2554 R_FreeTexture(r_shadow_bouncegridtexture);
2555 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);
2557 r_shadow_bouncegridtime = realtime;
2560 #define MAXPARTICLESPERLIGHT 262144
2561 #define MAXLIGHTSPERDRAW 1024
2563 static void R_Shadow_RenderParticlesForLight(rtlight_t *rtlight)
2569 int hitsupercontentsmask;
2572 int shootparticles = 0;
2575 unsigned int seed = 0;
2576 static unsigned short bouncelight_elements[MAXLIGHTSPERDRAW*36];
2577 static float vertex3f[MAXLIGHTSPERDRAW*24];
2578 static float lightorigin4f[MAXLIGHTSPERDRAW*32];
2579 static float color4f[MAXLIGHTSPERDRAW*32];
2580 float scaledpoints[8][3];
2584 rtlight_particle_t *p;
2585 vec_t wantparticles = 0;
2589 vec_t iparticlesize;
2595 vec3_t currentcolor;
2600 if (!rtlight->draw || !rtlight->isstatic || !r_shadow_usingdeferredprepass)
2602 if (r_shadow_particletrace.integer)
2604 radius = rtlight->radius * bound(0.0001f, r_shadow_particletrace_radiusscale.value, 1.0f) - r_shadow_particletrace_size.value;
2605 s = rtlight->radius / bound(1.0f, r_shadow_particletrace_particlespacing.value * r_shadow_particletrace_size.value, 1048576.0f);
2606 wantparticles = s*s;
2607 n = (int)bound(0, wantparticles, MAXPARTICLESPERLIGHT);
2611 shootparticles = (int)(n * r_shadow_particletrace_updatepercentage.value);
2612 if ((n && !rtlight->particlecache_particles) || rtlight->particlecache_maxparticles != n)
2614 if (rtlight->particlecache_particles)
2615 Mem_Free(rtlight->particlecache_particles);
2616 rtlight->particlecache_particles = NULL;
2617 rtlight->particlecache_numparticles = 0;
2618 rtlight->particlecache_maxparticles = n;
2619 rtlight->particlecache_updateparticle = 0;
2620 if (rtlight->particlecache_maxparticles)
2621 rtlight->particlecache_particles = (rtlight_particle_t *)Mem_Alloc(r_main_mempool, rtlight->particlecache_maxparticles * sizeof(*rtlight->particlecache_particles));
2622 shootparticles = n * 16;
2625 if (!rtlight->particlecache_maxparticles)
2628 // if (rtlight->particlecache_numparticles < rtlight->particlecache_maxparticles)
2629 // shootparticles = rtlight->particlecache_maxparticles;
2631 // if (rtlight->particlecache_numparticles >= rtlight->particlecache_maxparticles)
2632 // shootparticles = 0;
2634 maxbounce = bound(1, r_shadow_particletrace_maxbounce.integer, 16);
2635 //r_refdef.stats.lights_bouncelightsupdated += shootparticles;
2636 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2638 seed = rtlight->particlecache_updateparticle;
2639 VectorSet(shotcolor, 1.0f, 1.0f, 1.0f);
2640 VectorCopy(rtlight->shadoworigin, clipstart);
2641 VectorRandom(clipend);
2642 VectorMA(clipstart, radius, clipend, clipend);
2643 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
2644 bouncelimit = 1 + (rtlight->particlecache_updateparticle % maxbounce);
2645 for (bouncecount = 0;;bouncecount++)
2647 cliptrace = CL_TraceLine(clipstart, clipend, MOVE_NOMONSTERS, NULL, hitsupercontentsmask, true, false, NULL, true);
2648 //Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask);
2649 if (cliptrace.fraction >= 1.0f)
2651 if (VectorLength2(shotcolor) < (1.0f / 262144.0f))
2653 if (bouncecount >= bouncelimit)
2655 VectorCopy(cliptrace.endpos, rtlight->particlecache_particles[rtlight->particlecache_updateparticle].origin);
2656 VectorCopy(shotcolor, rtlight->particlecache_particles[rtlight->particlecache_updateparticle].color);
2657 rtlight->particlecache_updateparticle++;
2658 if (rtlight->particlecache_numparticles < rtlight->particlecache_updateparticle)
2659 rtlight->particlecache_numparticles = rtlight->particlecache_updateparticle;
2660 if (rtlight->particlecache_updateparticle >= rtlight->particlecache_maxparticles)
2662 rtlight->particlecache_updateparticle = 0;
2663 shotparticles = shootparticles;
2667 // scale down shot color by bounce intensity and texture color
2668 VectorScale(shotcolor, r_shadow_particletrace_bounceintensity.value, shotcolor);
2669 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2670 VectorMultiply(shotcolor, rsurface.texture->currentskinframe->avgcolor, shotcolor);
2671 // reflect the remaining portion of the line across plane normal
2672 //VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2673 //VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2674 // random direction, primarily along plane normal
2675 s = VectorDistance(cliptrace.endpos, clipend);
2676 VectorRandom(clipend);
2677 VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
2678 VectorNormalize(clipend);
2679 VectorScale(clipend, s, clipend);
2680 // calculate the new line start and end
2681 VectorCopy(cliptrace.endpos, clipstart);
2682 VectorAdd(clipstart, clipend, clipend);
2686 if (!rtlight->particlecache_numparticles)
2689 // render the particles as deferred lights
2690 // do global setup needed for the chosen lighting mode
2691 R_Shadow_RenderMode_Reset();
2692 r_shadow_rendermode = r_shadow_lightingrendermode;
2693 r_shadow_usingshadowmap2d = false;
2694 R_EntityMatrix(&identitymatrix);
2695 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2696 // only draw light where this geometry was already rendered AND the
2697 // stencil is 128 (values other than this mean shadow)
2698 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2699 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
2700 R_SetupShader_DeferredBounceLight();
2701 GL_ColorMask(1,1,1,1);
2702 GL_DepthMask(false);
2703 GL_DepthRange(0, 1);
2704 GL_PolygonOffset(0, 0);
2706 GL_DepthFunc(GL_GREATER);
2707 GL_CullFace(r_refdef.view.cullface_back);
2708 s = r_shadow_particletrace_intensity.value / (float)rtlight->particlecache_numparticles;
2709 VectorScale(rtlight->currentcolor, s, currentcolor);
2710 particlesize = bound(0.0001f, r_shadow_particletrace_size.value, 1024.0f);
2711 iparticlesize = 1.0f / particlesize;
2712 // VectorScale(r_refdef.view.forward, particlesize, offset);
2713 // VectorScale(r_refdef.view.left, -particlesize, right);
2714 // VectorScale(r_refdef.view.up, particlesize, up);
2715 org[3] = iparticlesize;
2718 lo4f = lightorigin4f;
2721 if (!bouncelight_elements[1])
2722 for (i = 0;i < MAXLIGHTSPERDRAW;i++)
2723 for (j = 0;j < 36;j++)
2724 bouncelight_elements[i*36+j] = i*8+bboxelements[j];
2725 for (j = 0;j < 8;j++)
2726 VectorScale(bboxpoints[j], particlesize, scaledpoints[j]);
2727 //r_refdef.stats.lights_bouncelightscounted += rtlight->particlecache_numparticles;
2728 for (j = 0, p = rtlight->particlecache_particles, n = rtlight->particlecache_numparticles;j < n;j++, p++)
2730 VectorCopy(p->origin, org);
2731 // org[3] is set above
2732 VectorMultiply(p->color, currentcolor, color);
2733 // color[3] is set above
2734 VectorAdd(scaledpoints[0], org, v3f + 0);
2735 VectorAdd(scaledpoints[1], org, v3f + 3);
2736 VectorAdd(scaledpoints[2], org, v3f + 6);
2737 VectorAdd(scaledpoints[3], org, v3f + 9);
2738 VectorAdd(scaledpoints[4], org, v3f + 12);
2739 VectorAdd(scaledpoints[5], org, v3f + 15);
2740 VectorAdd(scaledpoints[6], org, v3f + 18);
2741 VectorAdd(scaledpoints[7], org, v3f + 21);
2742 Vector4Copy(org, lo4f + 0);
2743 Vector4Copy(org, lo4f + 4);
2744 Vector4Copy(org, lo4f + 8);
2745 Vector4Copy(org, lo4f + 12);
2746 Vector4Copy(org, lo4f + 16);
2747 Vector4Copy(org, lo4f + 20);
2748 Vector4Copy(org, lo4f + 24);
2749 Vector4Copy(org, lo4f + 28);
2750 Vector4Copy(color, c4f + 0);
2751 Vector4Copy(color, c4f + 4);
2752 Vector4Copy(color, c4f + 8);
2753 Vector4Copy(color, c4f + 12);
2754 Vector4Copy(color, c4f + 16);
2755 Vector4Copy(color, c4f + 20);
2756 Vector4Copy(color, c4f + 24);
2757 Vector4Copy(color, c4f + 28);
2762 if (batchcount >= MAXLIGHTSPERDRAW)
2764 //r_refdef.stats.lights_bouncelightsdrawn += batchcount;
2765 R_Mesh_PrepareVertices_BounceLight_Arrays(batchcount*8, vertex3f, color4f, lightorigin4f);
2766 R_Mesh_Draw(0, batchcount*8, 0, batchcount*12, NULL, NULL, 0, bouncelight_elements, NULL, 0);
2768 lo4f = lightorigin4f;
2775 //r_refdef.stats.lights_bouncelightsdrawn += batchcount;
2776 R_Mesh_PrepareVertices_BounceLight_Arrays(batchcount*8, vertex3f, color4f, lightorigin4f);
2777 R_Mesh_Draw(0, batchcount*8, 0, batchcount*12, NULL, NULL, 0, bouncelight_elements, NULL, 0);
2779 lo4f = lightorigin4f;
2785 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2787 R_Shadow_RenderMode_Reset();
2788 GL_BlendFunc(GL_ONE, GL_ONE);
2789 GL_DepthRange(0, 1);
2790 GL_DepthTest(r_showshadowvolumes.integer < 2);
2791 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2792 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2793 GL_CullFace(GL_NONE);
2794 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2797 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2799 R_Shadow_RenderMode_Reset();
2800 GL_BlendFunc(GL_ONE, GL_ONE);
2801 GL_DepthRange(0, 1);
2802 GL_DepthTest(r_showlighting.integer < 2);
2803 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2805 GL_DepthFunc(GL_EQUAL);
2806 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2807 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2810 void R_Shadow_RenderMode_End(void)
2812 R_Shadow_RenderMode_Reset();
2813 R_Shadow_RenderMode_ActiveLight(NULL);
2815 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2816 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2819 int bboxedges[12][2] =
2838 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2840 if (!r_shadow_scissor.integer)
2842 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2843 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2844 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2845 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2848 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2849 return true; // invisible
2850 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2851 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2852 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2853 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2854 r_refdef.stats.lights_scissored++;
2858 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2861 const float *vertex3f;
2862 const float *normal3f;
2864 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2865 switch (r_shadow_rendermode)
2867 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2868 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2869 if (VectorLength2(diffusecolor) > 0)
2871 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)
2873 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2874 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2875 if ((dot = DotProduct(n, v)) < 0)
2877 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2878 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2881 VectorCopy(ambientcolor, color4f);
2882 if (r_refdef.fogenabled)
2885 f = RSurf_FogVertex(vertex3f);
2886 VectorScale(color4f, f, color4f);
2893 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2895 VectorCopy(ambientcolor, color4f);
2896 if (r_refdef.fogenabled)
2899 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2900 f = RSurf_FogVertex(vertex3f);
2901 VectorScale(color4f + 4*i, f, color4f);
2907 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2908 if (VectorLength2(diffusecolor) > 0)
2910 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)
2912 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2913 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2915 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2916 if ((dot = DotProduct(n, v)) < 0)
2918 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2919 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2920 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2921 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2925 color4f[0] = ambientcolor[0] * distintensity;
2926 color4f[1] = ambientcolor[1] * distintensity;
2927 color4f[2] = ambientcolor[2] * distintensity;
2929 if (r_refdef.fogenabled)
2932 f = RSurf_FogVertex(vertex3f);
2933 VectorScale(color4f, f, color4f);
2937 VectorClear(color4f);
2943 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2945 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2946 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2948 color4f[0] = ambientcolor[0] * distintensity;
2949 color4f[1] = ambientcolor[1] * distintensity;
2950 color4f[2] = ambientcolor[2] * distintensity;
2951 if (r_refdef.fogenabled)
2954 f = RSurf_FogVertex(vertex3f);
2955 VectorScale(color4f, f, color4f);
2959 VectorClear(color4f);
2964 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2965 if (VectorLength2(diffusecolor) > 0)
2967 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)
2969 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2970 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2972 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2973 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2974 if ((dot = DotProduct(n, v)) < 0)
2976 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2977 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2978 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2979 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2983 color4f[0] = ambientcolor[0] * distintensity;
2984 color4f[1] = ambientcolor[1] * distintensity;
2985 color4f[2] = ambientcolor[2] * distintensity;
2987 if (r_refdef.fogenabled)
2990 f = RSurf_FogVertex(vertex3f);
2991 VectorScale(color4f, f, color4f);
2995 VectorClear(color4f);
3001 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3003 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3004 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3006 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3007 color4f[0] = ambientcolor[0] * distintensity;
3008 color4f[1] = ambientcolor[1] * distintensity;
3009 color4f[2] = ambientcolor[2] * distintensity;
3010 if (r_refdef.fogenabled)
3013 f = RSurf_FogVertex(vertex3f);
3014 VectorScale(color4f, f, color4f);
3018 VectorClear(color4f);
3028 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3030 // used to display how many times a surface is lit for level design purposes
3031 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3032 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3036 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
3038 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3039 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
3040 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
3041 GL_DepthFunc(GL_EQUAL);
3043 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
3044 GL_DepthFunc(GL_LEQUAL);
3047 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3054 int newnumtriangles;
3058 int maxtriangles = 4096;
3059 static int newelements[4096*3];
3060 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3061 for (renders = 0;renders < 4;renders++)
3066 newnumtriangles = 0;
3068 // due to low fillrate on the cards this vertex lighting path is
3069 // designed for, we manually cull all triangles that do not
3070 // contain a lit vertex
3071 // this builds batches of triangles from multiple surfaces and
3072 // renders them at once
3073 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3075 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3077 if (newnumtriangles)
3079 newfirstvertex = min(newfirstvertex, e[0]);
3080 newlastvertex = max(newlastvertex, e[0]);
3084 newfirstvertex = e[0];
3085 newlastvertex = e[0];
3087 newfirstvertex = min(newfirstvertex, e[1]);
3088 newlastvertex = max(newlastvertex, e[1]);
3089 newfirstvertex = min(newfirstvertex, e[2]);
3090 newlastvertex = max(newlastvertex, e[2]);
3096 if (newnumtriangles >= maxtriangles)
3098 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3099 newnumtriangles = 0;
3105 if (newnumtriangles >= 1)
3107 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3110 // if we couldn't find any lit triangles, exit early
3113 // now reduce the intensity for the next overbright pass
3114 // we have to clamp to 0 here incase the drivers have improper
3115 // handling of negative colors
3116 // (some old drivers even have improper handling of >1 color)
3118 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3120 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3122 c[0] = max(0, c[0] - 1);
3123 c[1] = max(0, c[1] - 1);
3124 c[2] = max(0, c[2] - 1);
3136 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
3138 // OpenGL 1.1 path (anything)
3139 float ambientcolorbase[3], diffusecolorbase[3];
3140 float ambientcolorpants[3], diffusecolorpants[3];
3141 float ambientcolorshirt[3], diffusecolorshirt[3];
3142 const float *surfacecolor = rsurface.texture->dlightcolor;
3143 const float *surfacepants = rsurface.colormap_pantscolor;
3144 const float *surfaceshirt = rsurface.colormap_shirtcolor;
3145 rtexture_t *basetexture = rsurface.texture->basetexture;
3146 rtexture_t *pantstexture = rsurface.texture->pantstexture;
3147 rtexture_t *shirttexture = rsurface.texture->shirttexture;
3148 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3149 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3150 ambientscale *= 2 * r_refdef.view.colorscale;
3151 diffusescale *= 2 * r_refdef.view.colorscale;
3152 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3153 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3154 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3155 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3156 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3157 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
3158 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3159 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
3160 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3161 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
3162 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
3163 R_Mesh_TexBind(0, basetexture);
3164 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
3165 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
3166 switch(r_shadow_rendermode)
3168 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3169 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
3170 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3171 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3172 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3174 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3175 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
3176 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
3177 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
3178 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3180 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3181 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
3182 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3183 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3184 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3186 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3191 //R_Mesh_TexBind(0, basetexture);
3192 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
3195 R_Mesh_TexBind(0, pantstexture);
3196 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
3200 R_Mesh_TexBind(0, shirttexture);
3201 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
3205 extern cvar_t gl_lightmaps;
3206 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3208 float ambientscale, diffusescale, specularscale;
3210 float lightcolor[3];
3211 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
3212 ambientscale = rsurface.rtlight->ambientscale;
3213 diffusescale = rsurface.rtlight->diffusescale;
3214 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3215 if (!r_shadow_usenormalmap.integer)
3217 ambientscale += 1.0f * diffusescale;
3221 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
3223 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
3226 VectorNegate(lightcolor, lightcolor);
3227 switch(vid.renderpath)
3229 case RENDERPATH_GL11:
3230 case RENDERPATH_GL13:
3231 case RENDERPATH_GL20:
3232 case RENDERPATH_GLES2:
3233 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
3235 case RENDERPATH_D3D9:
3237 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
3240 case RENDERPATH_D3D10:
3241 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3243 case RENDERPATH_D3D11:
3244 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3246 case RENDERPATH_SOFT:
3247 DPSOFTRAST_BlendSubtract(true);
3251 RSurf_SetupDepthAndCulling();
3252 switch (r_shadow_rendermode)
3254 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3255 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3256 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
3258 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3259 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
3261 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3262 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3263 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3264 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3265 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
3268 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3273 switch(vid.renderpath)
3275 case RENDERPATH_GL11:
3276 case RENDERPATH_GL13:
3277 case RENDERPATH_GL20:
3278 case RENDERPATH_GLES2:
3279 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
3281 case RENDERPATH_D3D9:
3283 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
3286 case RENDERPATH_D3D10:
3287 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3289 case RENDERPATH_D3D11:
3290 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3292 case RENDERPATH_SOFT:
3293 DPSOFTRAST_BlendSubtract(false);
3299 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)
3301 matrix4x4_t tempmatrix = *matrix;
3302 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3304 // if this light has been compiled before, free the associated data
3305 R_RTLight_Uncompile(rtlight);
3307 // clear it completely to avoid any lingering data
3308 memset(rtlight, 0, sizeof(*rtlight));
3310 // copy the properties
3311 rtlight->matrix_lighttoworld = tempmatrix;
3312 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3313 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3314 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3315 VectorCopy(color, rtlight->color);
3316 rtlight->cubemapname[0] = 0;
3317 if (cubemapname && cubemapname[0])
3318 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3319 rtlight->shadow = shadow;
3320 rtlight->corona = corona;
3321 rtlight->style = style;
3322 rtlight->isstatic = isstatic;
3323 rtlight->coronasizescale = coronasizescale;
3324 rtlight->ambientscale = ambientscale;
3325 rtlight->diffusescale = diffusescale;
3326 rtlight->specularscale = specularscale;
3327 rtlight->flags = flags;
3329 // compute derived data
3330 //rtlight->cullradius = rtlight->radius;
3331 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3332 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3333 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3334 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3335 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3336 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3337 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3340 // compiles rtlight geometry
3341 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3342 void R_RTLight_Compile(rtlight_t *rtlight)
3345 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3346 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3347 entity_render_t *ent = r_refdef.scene.worldentity;
3348 dp_model_t *model = r_refdef.scene.worldmodel;
3349 unsigned char *data;
3352 // compile the light
3353 rtlight->compiled = true;
3354 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3355 rtlight->static_numleafs = 0;
3356 rtlight->static_numleafpvsbytes = 0;
3357 rtlight->static_leaflist = NULL;
3358 rtlight->static_leafpvs = NULL;
3359 rtlight->static_numsurfaces = 0;
3360 rtlight->static_surfacelist = NULL;
3361 rtlight->static_shadowmap_receivers = 0x3F;
3362 rtlight->static_shadowmap_casters = 0x3F;
3363 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3364 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3365 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3366 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3367 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3368 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3370 if (model && model->GetLightInfo)
3372 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3373 r_shadow_compilingrtlight = rtlight;
3374 R_FrameData_SetMark();
3375 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);
3376 R_FrameData_ReturnToMark();
3377 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3378 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3379 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3380 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3381 rtlight->static_numsurfaces = numsurfaces;
3382 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3383 rtlight->static_numleafs = numleafs;
3384 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3385 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3386 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3387 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3388 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3389 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3390 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3391 if (rtlight->static_numsurfaces)
3392 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3393 if (rtlight->static_numleafs)
3394 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3395 if (rtlight->static_numleafpvsbytes)
3396 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3397 if (rtlight->static_numshadowtrispvsbytes)
3398 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3399 if (rtlight->static_numlighttrispvsbytes)
3400 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3401 R_FrameData_SetMark();
3402 switch (rtlight->shadowmode)
3404 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3405 if (model->CompileShadowMap && rtlight->shadow)
3406 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3409 if (model->CompileShadowVolume && rtlight->shadow)
3410 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3413 R_FrameData_ReturnToMark();
3414 // now we're done compiling the rtlight
3415 r_shadow_compilingrtlight = NULL;
3419 // use smallest available cullradius - box radius or light radius
3420 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3421 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3423 shadowzpasstris = 0;
3424 if (rtlight->static_meshchain_shadow_zpass)
3425 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3426 shadowzpasstris += mesh->numtriangles;
3428 shadowzfailtris = 0;
3429 if (rtlight->static_meshchain_shadow_zfail)
3430 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3431 shadowzfailtris += mesh->numtriangles;
3434 if (rtlight->static_numlighttrispvsbytes)
3435 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3436 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3440 if (rtlight->static_numlighttrispvsbytes)
3441 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3442 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3445 if (developer_extra.integer)
3446 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);
3449 void R_RTLight_Uncompile(rtlight_t *rtlight)
3451 if (rtlight->compiled)
3453 if (rtlight->static_meshchain_shadow_zpass)
3454 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3455 rtlight->static_meshchain_shadow_zpass = NULL;
3456 if (rtlight->static_meshchain_shadow_zfail)
3457 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3458 rtlight->static_meshchain_shadow_zfail = NULL;
3459 if (rtlight->static_meshchain_shadow_shadowmap)
3460 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3461 rtlight->static_meshchain_shadow_shadowmap = NULL;
3462 // these allocations are grouped
3463 if (rtlight->static_surfacelist)
3464 Mem_Free(rtlight->static_surfacelist);
3465 rtlight->static_numleafs = 0;
3466 rtlight->static_numleafpvsbytes = 0;
3467 rtlight->static_leaflist = NULL;
3468 rtlight->static_leafpvs = NULL;
3469 rtlight->static_numsurfaces = 0;
3470 rtlight->static_surfacelist = NULL;
3471 rtlight->static_numshadowtrispvsbytes = 0;
3472 rtlight->static_shadowtrispvs = NULL;
3473 rtlight->static_numlighttrispvsbytes = 0;
3474 rtlight->static_lighttrispvs = NULL;
3475 rtlight->compiled = false;
3479 void R_Shadow_UncompileWorldLights(void)
3483 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3484 for (lightindex = 0;lightindex < range;lightindex++)
3486 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3489 R_RTLight_Uncompile(&light->rtlight);
3493 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3497 // reset the count of frustum planes
3498 // see rtlight->cached_frustumplanes definition for how much this array
3500 rtlight->cached_numfrustumplanes = 0;
3502 // haven't implemented a culling path for ortho rendering
3503 if (!r_refdef.view.useperspective)
3505 // check if the light is on screen and copy the 4 planes if it is
3506 for (i = 0;i < 4;i++)
3507 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3510 for (i = 0;i < 4;i++)
3511 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3516 // generate a deformed frustum that includes the light origin, this is
3517 // used to cull shadow casting surfaces that can not possibly cast a
3518 // shadow onto the visible light-receiving surfaces, which can be a
3521 // if the light origin is onscreen the result will be 4 planes exactly
3522 // if the light origin is offscreen on only one axis the result will
3523 // be exactly 5 planes (split-side case)
3524 // if the light origin is offscreen on two axes the result will be
3525 // exactly 4 planes (stretched corner case)
3526 for (i = 0;i < 4;i++)
3528 // quickly reject standard frustum planes that put the light
3529 // origin outside the frustum
3530 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3533 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3535 // if all the standard frustum planes were accepted, the light is onscreen
3536 // otherwise we need to generate some more planes below...
3537 if (rtlight->cached_numfrustumplanes < 4)
3539 // at least one of the stock frustum planes failed, so we need to
3540 // create one or two custom planes to enclose the light origin
3541 for (i = 0;i < 4;i++)
3543 // create a plane using the view origin and light origin, and a
3544 // single point from the frustum corner set
3545 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3546 VectorNormalize(plane.normal);
3547 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3548 // see if this plane is backwards and flip it if so
3549 for (j = 0;j < 4;j++)
3550 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3554 VectorNegate(plane.normal, plane.normal);
3556 // flipped plane, test again to see if it is now valid
3557 for (j = 0;j < 4;j++)
3558 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3560 // if the plane is still not valid, then it is dividing the
3561 // frustum and has to be rejected
3565 // we have created a valid plane, compute extra info
3566 PlaneClassify(&plane);
3568 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3570 // if we've found 5 frustum planes then we have constructed a
3571 // proper split-side case and do not need to keep searching for
3572 // planes to enclose the light origin
3573 if (rtlight->cached_numfrustumplanes == 5)
3581 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3583 plane = rtlight->cached_frustumplanes[i];
3584 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));
3589 // now add the light-space box planes if the light box is rotated, as any
3590 // caster outside the oriented light box is irrelevant (even if it passed
3591 // the worldspace light box, which is axial)
3592 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3594 for (i = 0;i < 6;i++)
3598 v[i >> 1] = (i & 1) ? -1 : 1;
3599 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3600 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3601 plane.dist = VectorNormalizeLength(plane.normal);
3602 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3603 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3609 // add the world-space reduced box planes
3610 for (i = 0;i < 6;i++)
3612 VectorClear(plane.normal);
3613 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3614 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3615 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3624 // reduce all plane distances to tightly fit the rtlight cull box, which
3626 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3627 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3628 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3629 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3630 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3631 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3632 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3633 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3634 oldnum = rtlight->cached_numfrustumplanes;
3635 rtlight->cached_numfrustumplanes = 0;
3636 for (j = 0;j < oldnum;j++)
3638 // find the nearest point on the box to this plane
3639 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3640 for (i = 1;i < 8;i++)
3642 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3643 if (bestdist > dist)
3646 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);
3647 // if the nearest point is near or behind the plane, we want this
3648 // plane, otherwise the plane is useless as it won't cull anything
3649 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3651 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3652 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3659 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3663 RSurf_ActiveWorldEntity();
3665 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3668 GL_CullFace(GL_NONE);
3669 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3670 for (;mesh;mesh = mesh->next)
3672 if (!mesh->sidetotals[r_shadow_shadowmapside])
3674 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3675 if (mesh->vertex3fbuffer)
3676 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3678 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3679 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);
3683 else if (r_refdef.scene.worldentity->model)
3684 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);
3686 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3689 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3691 qboolean zpass = false;
3694 int surfacelistindex;
3695 msurface_t *surface;
3697 // if triangle neighbors are disabled, shadowvolumes are disabled
3698 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
3701 RSurf_ActiveWorldEntity();
3703 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3706 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3708 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3709 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3711 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3712 for (;mesh;mesh = mesh->next)
3714 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3715 if (mesh->vertex3fbuffer)
3716 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3718 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3719 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3721 // increment stencil if frontface is infront of depthbuffer
3722 GL_CullFace(r_refdef.view.cullface_back);
3723 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3724 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);
3725 // decrement stencil if backface is infront of depthbuffer
3726 GL_CullFace(r_refdef.view.cullface_front);
3727 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3729 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3731 // decrement stencil if backface is behind depthbuffer
3732 GL_CullFace(r_refdef.view.cullface_front);
3733 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3734 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);
3735 // increment stencil if frontface is behind depthbuffer
3736 GL_CullFace(r_refdef.view.cullface_back);
3737 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3739 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);
3743 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3745 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3746 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3747 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3749 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3750 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3751 if (CHECKPVSBIT(trispvs, t))
3752 shadowmarklist[numshadowmark++] = t;
3754 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);
3756 else if (numsurfaces)
3758 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);
3761 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3764 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3766 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3767 vec_t relativeshadowradius;
3768 RSurf_ActiveModelEntity(ent, false, false, false);
3769 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3770 // we need to re-init the shader for each entity because the matrix changed
3771 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3772 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3773 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3774 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3775 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3776 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3777 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3778 switch (r_shadow_rendermode)
3780 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3781 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3784 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3787 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3790 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3792 // set up properties for rendering light onto this entity
3793 RSurf_ActiveModelEntity(ent, true, true, false);
3794 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3795 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3796 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3797 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3800 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3802 if (!r_refdef.scene.worldmodel->DrawLight)
3805 // set up properties for rendering light onto this entity
3806 RSurf_ActiveWorldEntity();
3807 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3808 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3809 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3810 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3812 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3814 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3817 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3819 dp_model_t *model = ent->model;
3820 if (!model->DrawLight)
3823 R_Shadow_SetupEntityLight(ent);
3825 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3827 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3830 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3834 int numleafs, numsurfaces;
3835 int *leaflist, *surfacelist;
3836 unsigned char *leafpvs;
3837 unsigned char *shadowtrispvs;
3838 unsigned char *lighttrispvs;
3839 //unsigned char *surfacesides;
3840 int numlightentities;
3841 int numlightentities_noselfshadow;
3842 int numshadowentities;
3843 int numshadowentities_noselfshadow;
3844 static entity_render_t *lightentities[MAX_EDICTS];
3845 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3846 static entity_render_t *shadowentities[MAX_EDICTS];
3847 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3850 rtlight->draw = false;
3852 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3853 // skip lights that are basically invisible (color 0 0 0)
3854 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3856 // loading is done before visibility checks because loading should happen
3857 // all at once at the start of a level, not when it stalls gameplay.
3858 // (especially important to benchmarks)
3860 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3862 if (rtlight->compiled)
3863 R_RTLight_Uncompile(rtlight);
3864 R_RTLight_Compile(rtlight);
3868 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3870 // look up the light style value at this time
3871 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3872 VectorScale(rtlight->color, f, rtlight->currentcolor);
3874 if (rtlight->selected)
3876 f = 2 + sin(realtime * M_PI * 4.0);
3877 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3881 // if lightstyle is currently off, don't draw the light
3882 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3885 // skip processing on corona-only lights
3889 // if the light box is offscreen, skip it
3890 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3893 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3894 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3896 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3898 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3900 // compiled light, world available and can receive realtime lighting
3901 // retrieve leaf information
3902 numleafs = rtlight->static_numleafs;
3903 leaflist = rtlight->static_leaflist;
3904 leafpvs = rtlight->static_leafpvs;
3905 numsurfaces = rtlight->static_numsurfaces;
3906 surfacelist = rtlight->static_surfacelist;
3907 //surfacesides = NULL;
3908 shadowtrispvs = rtlight->static_shadowtrispvs;
3909 lighttrispvs = rtlight->static_lighttrispvs;
3911 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3913 // dynamic light, world available and can receive realtime lighting
3914 // calculate lit surfaces and leafs
3915 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);
3916 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3917 leaflist = r_shadow_buffer_leaflist;
3918 leafpvs = r_shadow_buffer_leafpvs;
3919 surfacelist = r_shadow_buffer_surfacelist;
3920 //surfacesides = r_shadow_buffer_surfacesides;
3921 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3922 lighttrispvs = r_shadow_buffer_lighttrispvs;
3923 // if the reduced leaf bounds are offscreen, skip it
3924 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3935 //surfacesides = NULL;
3936 shadowtrispvs = NULL;
3937 lighttrispvs = NULL;
3939 // check if light is illuminating any visible leafs
3942 for (i = 0;i < numleafs;i++)
3943 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3949 // make a list of lit entities and shadow casting entities
3950 numlightentities = 0;
3951 numlightentities_noselfshadow = 0;
3952 numshadowentities = 0;
3953 numshadowentities_noselfshadow = 0;
3955 // add dynamic entities that are lit by the light
3956 for (i = 0;i < r_refdef.scene.numentities;i++)
3959 entity_render_t *ent = r_refdef.scene.entities[i];
3961 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3963 // skip the object entirely if it is not within the valid
3964 // shadow-casting region (which includes the lit region)
3965 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3967 if (!(model = ent->model))
3969 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3971 // this entity wants to receive light, is visible, and is
3972 // inside the light box
3973 // TODO: check if the surfaces in the model can receive light
3974 // so now check if it's in a leaf seen by the light
3975 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))
3977 if (ent->flags & RENDER_NOSELFSHADOW)
3978 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3980 lightentities[numlightentities++] = ent;
3981 // since it is lit, it probably also casts a shadow...
3982 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3983 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3984 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3986 // note: exterior models without the RENDER_NOSELFSHADOW
3987 // flag still create a RENDER_NOSELFSHADOW shadow but
3988 // are lit normally, this means that they are
3989 // self-shadowing but do not shadow other
3990 // RENDER_NOSELFSHADOW entities such as the gun
3991 // (very weird, but keeps the player shadow off the gun)
3992 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3993 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3995 shadowentities[numshadowentities++] = ent;
3998 else if (ent->flags & RENDER_SHADOW)
4000 // this entity is not receiving light, but may still need to
4002 // TODO: check if the surfaces in the model can cast shadow
4003 // now check if it is in a leaf seen by the light
4004 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))
4006 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4007 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4008 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4010 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4011 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4013 shadowentities[numshadowentities++] = ent;
4018 // return if there's nothing at all to light
4019 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4022 // count this light in the r_speeds
4023 r_refdef.stats.lights++;
4025 // flag it as worth drawing later
4026 rtlight->draw = true;
4028 // cache all the animated entities that cast a shadow but are not visible
4029 for (i = 0;i < numshadowentities;i++)
4030 if (!shadowentities[i]->animcache_vertex3f)
4031 R_AnimCache_GetEntity(shadowentities[i], false, false);
4032 for (i = 0;i < numshadowentities_noselfshadow;i++)
4033 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
4034 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4036 // allocate some temporary memory for rendering this light later in the frame
4037 // reusable buffers need to be copied, static data can be used as-is
4038 rtlight->cached_numlightentities = numlightentities;
4039 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
4040 rtlight->cached_numshadowentities = numshadowentities;
4041 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4042 rtlight->cached_numsurfaces = numsurfaces;
4043 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4044 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4045 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4046 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4047 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4049 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4050 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4051 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4052 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4053 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4057 // compiled light data
4058 rtlight->cached_shadowtrispvs = shadowtrispvs;
4059 rtlight->cached_lighttrispvs = lighttrispvs;
4060 rtlight->cached_surfacelist = surfacelist;
4064 void R_Shadow_DrawLight(rtlight_t *rtlight)
4068 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4069 int numlightentities;
4070 int numlightentities_noselfshadow;
4071 int numshadowentities;
4072 int numshadowentities_noselfshadow;
4073 entity_render_t **lightentities;
4074 entity_render_t **lightentities_noselfshadow;
4075 entity_render_t **shadowentities;
4076 entity_render_t **shadowentities_noselfshadow;
4078 static unsigned char entitysides[MAX_EDICTS];
4079 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4080 vec3_t nearestpoint;
4082 qboolean castshadows;
4085 // check if we cached this light this frame (meaning it is worth drawing)
4089 numlightentities = rtlight->cached_numlightentities;
4090 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4091 numshadowentities = rtlight->cached_numshadowentities;
4092 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4093 numsurfaces = rtlight->cached_numsurfaces;
4094 lightentities = rtlight->cached_lightentities;
4095 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4096 shadowentities = rtlight->cached_shadowentities;
4097 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4098 shadowtrispvs = rtlight->cached_shadowtrispvs;
4099 lighttrispvs = rtlight->cached_lighttrispvs;
4100 surfacelist = rtlight->cached_surfacelist;
4102 // set up a scissor rectangle for this light
4103 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4106 // don't let sound skip if going slow
4107 if (r_refdef.scene.extraupdate)
4110 // make this the active rtlight for rendering purposes
4111 R_Shadow_RenderMode_ActiveLight(rtlight);
4113 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4115 // optionally draw visible shape of the shadow volumes
4116 // for performance analysis by level designers
4117 R_Shadow_RenderMode_VisibleShadowVolumes();
4119 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4120 for (i = 0;i < numshadowentities;i++)
4121 R_Shadow_DrawEntityShadow(shadowentities[i]);
4122 for (i = 0;i < numshadowentities_noselfshadow;i++)
4123 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4124 R_Shadow_RenderMode_VisibleLighting(false, false);
4127 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4129 // optionally draw the illuminated areas
4130 // for performance analysis by level designers
4131 R_Shadow_RenderMode_VisibleLighting(false, false);
4133 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4134 for (i = 0;i < numlightentities;i++)
4135 R_Shadow_DrawEntityLight(lightentities[i]);
4136 for (i = 0;i < numlightentities_noselfshadow;i++)
4137 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4140 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4142 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4143 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4144 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4145 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4147 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
4148 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4149 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4151 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4157 int receivermask = 0;
4158 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4159 Matrix4x4_Abs(&radiustolight);
4161 r_shadow_shadowmaplod = 0;
4162 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4163 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
4164 r_shadow_shadowmaplod = i;
4166 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4168 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4170 surfacesides = NULL;
4173 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4175 castermask = rtlight->static_shadowmap_casters;
4176 receivermask = rtlight->static_shadowmap_receivers;
4180 surfacesides = r_shadow_buffer_surfacesides;
4181 for(i = 0;i < numsurfaces;i++)
4183 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4184 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4185 castermask |= surfacesides[i];
4186 receivermask |= surfacesides[i];
4190 if (receivermask < 0x3F)
4192 for (i = 0;i < numlightentities;i++)
4193 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4194 if (receivermask < 0x3F)
4195 for(i = 0; i < numlightentities_noselfshadow;i++)
4196 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4199 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4203 for (i = 0;i < numshadowentities;i++)
4204 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4205 for (i = 0;i < numshadowentities_noselfshadow;i++)
4206 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4209 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4211 // render shadow casters into 6 sided depth texture
4212 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4214 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
4215 if (! (castermask & (1 << side))) continue;
4217 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4218 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4219 R_Shadow_DrawEntityShadow(shadowentities[i]);
4222 if (numlightentities_noselfshadow)
4224 // render lighting using the depth texture as shadowmap
4225 // draw lighting in the unmasked areas
4226 R_Shadow_RenderMode_Lighting(false, false, true);
4227 for (i = 0;i < numlightentities_noselfshadow;i++)
4228 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4231 // render shadow casters into 6 sided depth texture
4232 if (numshadowentities_noselfshadow)
4234 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4236 R_Shadow_RenderMode_ShadowMap(side, 0, size);
4237 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
4238 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4242 // render lighting using the depth texture as shadowmap
4243 // draw lighting in the unmasked areas
4244 R_Shadow_RenderMode_Lighting(false, false, true);
4245 // draw lighting in the unmasked areas
4247 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4248 for (i = 0;i < numlightentities;i++)
4249 R_Shadow_DrawEntityLight(lightentities[i]);
4251 else if (castshadows && vid.stencil)
4253 // draw stencil shadow volumes to mask off pixels that are in shadow
4254 // so that they won't receive lighting
4255 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4256 R_Shadow_ClearStencil();
4259 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4260 for (i = 0;i < numshadowentities;i++)
4261 R_Shadow_DrawEntityShadow(shadowentities[i]);
4263 // draw lighting in the unmasked areas
4264 R_Shadow_RenderMode_Lighting(true, false, false);
4265 for (i = 0;i < numlightentities_noselfshadow;i++)
4266 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4268 for (i = 0;i < numshadowentities_noselfshadow;i++)
4269 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4271 // draw lighting in the unmasked areas
4272 R_Shadow_RenderMode_Lighting(true, false, false);
4274 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4275 for (i = 0;i < numlightentities;i++)
4276 R_Shadow_DrawEntityLight(lightentities[i]);
4280 // draw lighting in the unmasked areas
4281 R_Shadow_RenderMode_Lighting(false, false, false);
4283 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4284 for (i = 0;i < numlightentities;i++)
4285 R_Shadow_DrawEntityLight(lightentities[i]);
4286 for (i = 0;i < numlightentities_noselfshadow;i++)
4287 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4290 if (r_shadow_usingdeferredprepass)
4292 // when rendering deferred lighting, we simply rasterize the box
4293 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4294 R_Shadow_RenderMode_DrawDeferredLight(false, true);
4295 else if (castshadows && vid.stencil)
4296 R_Shadow_RenderMode_DrawDeferredLight(true, false);
4298 R_Shadow_RenderMode_DrawDeferredLight(false, false);
4301 if (r_shadow_particletrace.integer)
4302 R_Shadow_RenderParticlesForLight(rtlight);
4305 static void R_Shadow_FreeDeferred(void)
4307 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
4308 r_shadow_prepassgeometryfbo = 0;
4310 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
4311 r_shadow_prepasslightingdiffusespecularfbo = 0;
4313 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
4314 r_shadow_prepasslightingdiffusefbo = 0;
4316 if (r_shadow_prepassgeometrydepthtexture)
4317 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
4318 r_shadow_prepassgeometrydepthtexture = NULL;
4320 if (r_shadow_prepassgeometrydepthcolortexture)
4321 R_FreeTexture(r_shadow_prepassgeometrydepthcolortexture);
4322 r_shadow_prepassgeometrydepthcolortexture = NULL;
4324 if (r_shadow_prepassgeometrynormalmaptexture)
4325 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4326 r_shadow_prepassgeometrynormalmaptexture = NULL;
4328 if (r_shadow_prepasslightingdiffusetexture)
4329 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
4330 r_shadow_prepasslightingdiffusetexture = NULL;
4332 if (r_shadow_prepasslightingspeculartexture)
4333 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4334 r_shadow_prepasslightingspeculartexture = NULL;
4337 void R_Shadow_DrawPrepass(void)
4345 entity_render_t *ent;
4346 float clearcolor[4];
4348 R_Mesh_ResetTextureState();
4350 GL_ColorMask(1,1,1,1);
4351 GL_BlendFunc(GL_ONE, GL_ZERO);
4354 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4355 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4356 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4357 if (r_timereport_active)
4358 R_TimeReport("prepasscleargeom");
4360 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4361 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4362 if (r_timereport_active)
4363 R_TimeReport("prepassworld");
4365 for (i = 0;i < r_refdef.scene.numentities;i++)
4367 if (!r_refdef.viewcache.entityvisible[i])
4369 ent = r_refdef.scene.entities[i];
4370 if (ent->model && ent->model->DrawPrepass != NULL)
4371 ent->model->DrawPrepass(ent);
4374 if (r_timereport_active)
4375 R_TimeReport("prepassmodels");
4377 GL_DepthMask(false);
4378 GL_ColorMask(1,1,1,1);
4381 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4382 Vector4Set(clearcolor, 0, 0, 0, 0);
4383 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4384 if (r_timereport_active)
4385 R_TimeReport("prepassclearlit");
4387 R_Shadow_RenderMode_Begin();
4389 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4390 if (r_shadow_debuglight.integer >= 0)
4392 lightindex = r_shadow_debuglight.integer;
4393 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4394 if (light && (light->flags & flag) && light->rtlight.draw)
4395 R_Shadow_DrawLight(&light->rtlight);
4399 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4400 for (lightindex = 0;lightindex < range;lightindex++)
4402 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4403 if (light && (light->flags & flag) && light->rtlight.draw)
4404 R_Shadow_DrawLight(&light->rtlight);
4407 if (r_refdef.scene.rtdlight)
4408 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4409 if (r_refdef.scene.lights[lnum]->draw)
4410 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4412 R_Mesh_ResetRenderTargets();
4414 R_Shadow_RenderMode_End();
4416 if (r_timereport_active)
4417 R_TimeReport("prepasslights");
4420 void R_Shadow_DrawLightSprites(void);
4421 void R_Shadow_PrepareLights(void)
4431 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4432 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4433 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
4434 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4435 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4436 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4437 R_Shadow_FreeShadowMaps();
4439 r_shadow_usingshadowmaportho = false;
4441 switch (vid.renderpath)
4443 case RENDERPATH_GL20:
4444 case RENDERPATH_D3D9:
4445 case RENDERPATH_D3D10:
4446 case RENDERPATH_D3D11:
4447 case RENDERPATH_SOFT:
4448 case RENDERPATH_GLES2:
4449 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4451 r_shadow_usingdeferredprepass = false;
4452 if (r_shadow_prepass_width)
4453 R_Shadow_FreeDeferred();
4454 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4458 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4460 R_Shadow_FreeDeferred();
4462 r_shadow_usingdeferredprepass = true;
4463 r_shadow_prepass_width = vid.width;
4464 r_shadow_prepass_height = vid.height;
4465 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4466 switch (vid.renderpath)
4468 case RENDERPATH_D3D9:
4469 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);
4474 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);
4475 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);
4476 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);
4478 // set up the geometry pass fbo (depth + normalmap)
4479 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4480 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4481 // render depth into one texture and normalmap into the other
4482 if (qglDrawBuffersARB)
4484 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4485 qglReadBuffer(GL_NONE);CHECKGLERROR
4486 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4487 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4489 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4490 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4491 r_shadow_usingdeferredprepass = false;
4495 // set up the lighting pass fbo (diffuse + specular)
4496 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4497 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4498 // render diffuse into one texture and specular into another,
4499 // with depth and normalmap bound as textures,
4500 // with depth bound as attachment as well
4501 if (qglDrawBuffersARB)
4503 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4504 qglReadBuffer(GL_NONE);CHECKGLERROR
4505 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4506 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4508 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4509 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4510 r_shadow_usingdeferredprepass = false;
4514 // set up the lighting pass fbo (diffuse)
4515 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4516 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4517 // render diffuse into one texture,
4518 // with depth and normalmap bound as textures,
4519 // with depth bound as attachment as well
4520 if (qglDrawBuffersARB)
4522 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4523 qglReadBuffer(GL_NONE);CHECKGLERROR
4524 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4525 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4527 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4528 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4529 r_shadow_usingdeferredprepass = false;
4534 case RENDERPATH_GL13:
4535 case RENDERPATH_GL11:
4536 r_shadow_usingdeferredprepass = false;
4540 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);
4542 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4543 if (r_shadow_debuglight.integer >= 0)
4545 lightindex = r_shadow_debuglight.integer;
4546 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4547 if (light && (light->flags & flag))
4548 R_Shadow_PrepareLight(&light->rtlight);
4552 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4553 for (lightindex = 0;lightindex < range;lightindex++)
4555 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4556 if (light && (light->flags & flag))
4557 R_Shadow_PrepareLight(&light->rtlight);
4560 if (r_refdef.scene.rtdlight)
4562 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4563 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4565 else if(gl_flashblend.integer)
4567 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4569 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4570 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4571 VectorScale(rtlight->color, f, rtlight->currentcolor);
4575 if (r_editlights.integer)
4576 R_Shadow_DrawLightSprites();
4578 R_Shadow_UpdateBounceGridTexture();
4581 void R_Shadow_DrawLights(void)
4589 R_Shadow_RenderMode_Begin();
4591 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4592 if (r_shadow_debuglight.integer >= 0)
4594 lightindex = r_shadow_debuglight.integer;
4595 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4596 if (light && (light->flags & flag))
4597 R_Shadow_DrawLight(&light->rtlight);
4601 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4602 for (lightindex = 0;lightindex < range;lightindex++)
4604 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4605 if (light && (light->flags & flag))
4606 R_Shadow_DrawLight(&light->rtlight);
4609 if (r_refdef.scene.rtdlight)
4610 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4611 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4613 R_Shadow_RenderMode_End();
4616 extern const float r_screenvertex3f[12];
4617 extern void R_SetupView(qboolean allowwaterclippingplane);
4618 extern void R_ResetViewRendering3D(void);
4619 extern void R_ResetViewRendering2D(void);
4620 extern cvar_t r_shadows;
4621 extern cvar_t r_shadows_darken;
4622 extern cvar_t r_shadows_drawafterrtlighting;
4623 extern cvar_t r_shadows_castfrombmodels;
4624 extern cvar_t r_shadows_throwdistance;
4625 extern cvar_t r_shadows_throwdirection;
4626 extern cvar_t r_shadows_focus;
4627 extern cvar_t r_shadows_shadowmapscale;
4629 void R_Shadow_PrepareModelShadows(void)
4632 float scale, size, radius, dot1, dot2;
4633 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4634 entity_render_t *ent;
4636 if (!r_refdef.scene.numentities)
4639 switch (r_shadow_shadowmode)
4641 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4642 if (r_shadows.integer >= 2)
4645 case R_SHADOW_SHADOWMODE_STENCIL:
4646 for (i = 0;i < r_refdef.scene.numentities;i++)
4648 ent = r_refdef.scene.entities[i];
4649 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4650 R_AnimCache_GetEntity(ent, false, false);
4657 size = 2*r_shadow_shadowmapmaxsize;
4658 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4659 radius = 0.5f * size / scale;
4661 Math_atov(r_shadows_throwdirection.string, shadowdir);
4662 VectorNormalize(shadowdir);
4663 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4664 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4665 if (fabs(dot1) <= fabs(dot2))
4666 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4668 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4669 VectorNormalize(shadowforward);
4670 CrossProduct(shadowdir, shadowforward, shadowright);
4671 Math_atov(r_shadows_focus.string, shadowfocus);
4672 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4673 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4674 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4675 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4676 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4678 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4680 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4681 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4682 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4683 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4684 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4685 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4687 for (i = 0;i < r_refdef.scene.numentities;i++)
4689 ent = r_refdef.scene.entities[i];
4690 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4692 // cast shadows from anything of the map (submodels are optional)
4693 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4694 R_AnimCache_GetEntity(ent, false, false);
4698 void R_DrawModelShadowMaps(void)
4701 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4702 entity_render_t *ent;
4703 vec3_t relativelightorigin;
4704 vec3_t relativelightdirection, relativeforward, relativeright;
4705 vec3_t relativeshadowmins, relativeshadowmaxs;
4706 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4708 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4709 r_viewport_t viewport;
4711 float clearcolor[4];
4713 if (!r_refdef.scene.numentities)
4716 switch (r_shadow_shadowmode)
4718 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4724 R_ResetViewRendering3D();
4725 R_Shadow_RenderMode_Begin();
4726 R_Shadow_RenderMode_ActiveLight(NULL);
4728 switch (r_shadow_shadowmode)
4730 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4731 if (!r_shadow_shadowmap2dtexture)
4732 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4733 fbo = r_shadow_fbo2d;
4734 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4735 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4736 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4742 size = 2*r_shadow_shadowmapmaxsize;
4743 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4744 radius = 0.5f / scale;
4745 nearclip = -r_shadows_throwdistance.value;
4746 farclip = r_shadows_throwdistance.value;
4747 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4749 r_shadow_shadowmap_parameters[0] = size;
4750 r_shadow_shadowmap_parameters[1] = size;
4751 r_shadow_shadowmap_parameters[2] = 1.0;
4752 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4754 Math_atov(r_shadows_throwdirection.string, shadowdir);
4755 VectorNormalize(shadowdir);
4756 Math_atov(r_shadows_focus.string, shadowfocus);
4757 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4758 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4759 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4760 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4761 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4762 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4763 if (fabs(dot1) <= fabs(dot2))
4764 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4766 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4767 VectorNormalize(shadowforward);
4768 VectorM(scale, shadowforward, &m[0]);
4769 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4771 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4772 CrossProduct(shadowdir, shadowforward, shadowright);
4773 VectorM(scale, shadowright, &m[4]);
4774 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4775 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4776 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4777 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4778 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4779 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4781 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4783 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
4784 R_SetupShader_DepthOrShadow();
4785 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4788 R_SetViewport(&viewport);
4789 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4790 Vector4Set(clearcolor, 1,1,1,1);
4791 // in D3D9 we have to render to a color texture shadowmap
4792 // in GL we render directly to a depth texture only
4793 if (r_shadow_shadowmap2dtexture)
4794 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4796 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4797 // render into a slightly restricted region so that the borders of the
4798 // shadowmap area fade away, rather than streaking across everything
4799 // outside the usable area
4800 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4804 R_Mesh_ResetRenderTargets();
4805 R_SetupShader_ShowDepth();
4806 GL_ColorMask(1,1,1,1);
4807 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4810 for (i = 0;i < r_refdef.scene.numentities;i++)
4812 ent = r_refdef.scene.entities[i];
4814 // cast shadows from anything of the map (submodels are optional)
4815 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4817 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4818 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4819 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4820 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4821 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4822 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4823 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4824 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4825 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4826 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4827 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4828 RSurf_ActiveModelEntity(ent, false, false, false);
4829 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4830 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4837 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4839 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4841 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4842 Cvar_SetValueQuick(&r_test, 0);
4847 R_Shadow_RenderMode_End();
4849 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4850 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4851 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4852 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4853 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4854 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4856 switch (vid.renderpath)
4858 case RENDERPATH_GL11:
4859 case RENDERPATH_GL13:
4860 case RENDERPATH_GL20:
4861 case RENDERPATH_SOFT:
4862 case RENDERPATH_GLES2:
4864 case RENDERPATH_D3D9:
4865 case RENDERPATH_D3D10:
4866 case RENDERPATH_D3D11:
4867 #ifdef OPENGL_ORIENTATION
4868 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4869 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
4870 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
4871 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
4873 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4874 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
4875 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
4876 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
4881 r_shadow_usingshadowmaportho = true;
4882 switch (r_shadow_shadowmode)
4884 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4885 r_shadow_usingshadowmap2d = true;
4892 void R_DrawModelShadows(void)
4895 float relativethrowdistance;
4896 entity_render_t *ent;
4897 vec3_t relativelightorigin;
4898 vec3_t relativelightdirection;
4899 vec3_t relativeshadowmins, relativeshadowmaxs;
4900 vec3_t tmp, shadowdir;
4902 if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4905 R_ResetViewRendering3D();
4906 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4907 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4908 R_Shadow_RenderMode_Begin();
4909 R_Shadow_RenderMode_ActiveLight(NULL);
4910 r_shadow_lightscissor[0] = r_refdef.view.x;
4911 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4912 r_shadow_lightscissor[2] = r_refdef.view.width;
4913 r_shadow_lightscissor[3] = r_refdef.view.height;
4914 R_Shadow_RenderMode_StencilShadowVolumes(false);
4917 if (r_shadows.integer == 2)
4919 Math_atov(r_shadows_throwdirection.string, shadowdir);
4920 VectorNormalize(shadowdir);
4923 R_Shadow_ClearStencil();
4925 for (i = 0;i < r_refdef.scene.numentities;i++)
4927 ent = r_refdef.scene.entities[i];
4929 // cast shadows from anything of the map (submodels are optional)
4930 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4932 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4933 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4934 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4935 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4936 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4939 if(ent->entitynumber != 0)
4941 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4943 // FIXME handle this
4944 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4948 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4949 int entnum, entnum2, recursion;
4950 entnum = entnum2 = ent->entitynumber;
4951 for(recursion = 32; recursion > 0; --recursion)
4953 entnum2 = cl.entities[entnum].state_current.tagentity;
4954 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4959 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4961 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4962 // transform into modelspace of OUR entity
4963 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4964 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4967 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4971 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4974 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4975 RSurf_ActiveModelEntity(ent, false, false, false);
4976 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4977 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4981 // not really the right mode, but this will disable any silly stencil features
4982 R_Shadow_RenderMode_End();
4984 // set up ortho view for rendering this pass
4985 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4986 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4987 //GL_ScissorTest(true);
4988 //R_EntityMatrix(&identitymatrix);
4989 //R_Mesh_ResetTextureState();
4990 R_ResetViewRendering2D();
4992 // set up a darkening blend on shadowed areas
4993 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4994 //GL_DepthRange(0, 1);
4995 //GL_DepthTest(false);
4996 //GL_DepthMask(false);
4997 //GL_PolygonOffset(0, 0);CHECKGLERROR
4998 GL_Color(0, 0, 0, r_shadows_darken.value);
4999 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5000 //GL_DepthFunc(GL_ALWAYS);
5001 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5003 // apply the blend to the shadowed areas
5004 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5005 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
5006 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5008 // restore the viewport
5009 R_SetViewport(&r_refdef.view.viewport);
5011 // restore other state to normal
5012 //R_Shadow_RenderMode_End();
5015 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5018 vec3_t centerorigin;
5020 // if it's too close, skip it
5021 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5023 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5026 if (usequery && r_numqueries + 2 <= r_maxqueries)
5028 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5029 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5030 // 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
5031 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5033 switch(vid.renderpath)
5035 case RENDERPATH_GL20:
5036 case RENDERPATH_GL13:
5037 case RENDERPATH_GL11:
5038 case RENDERPATH_GLES2:
5040 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5041 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5042 GL_DepthFunc(GL_ALWAYS);
5043 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5044 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
5045 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5046 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5047 GL_DepthFunc(GL_LEQUAL);
5048 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5049 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5050 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
5051 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5052 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5055 case RENDERPATH_D3D9:
5056 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5058 case RENDERPATH_D3D10:
5059 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5061 case RENDERPATH_D3D11:
5062 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5064 case RENDERPATH_SOFT:
5065 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5069 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5072 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5074 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5077 GLint allpixels = 0, visiblepixels = 0;
5078 // now we have to check the query result
5079 if (rtlight->corona_queryindex_visiblepixels)
5081 switch(vid.renderpath)
5083 case RENDERPATH_GL20:
5084 case RENDERPATH_GL13:
5085 case RENDERPATH_GL11:
5086 case RENDERPATH_GLES2:
5088 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5089 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5092 case RENDERPATH_D3D9:
5093 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5095 case RENDERPATH_D3D10:
5096 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5098 case RENDERPATH_D3D11:
5099 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5101 case RENDERPATH_SOFT:
5102 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5105 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
5106 if (visiblepixels < 1 || allpixels < 1)
5108 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5109 cscale *= rtlight->corona_visibility;
5113 // FIXME: these traces should scan all render entities instead of cl.world
5114 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
5117 VectorScale(rtlight->currentcolor, cscale, color);
5118 if (VectorLength(color) > (1.0f / 256.0f))
5121 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
5124 VectorNegate(color, color);
5125 switch(vid.renderpath)
5127 case RENDERPATH_GL11:
5128 case RENDERPATH_GL13:
5129 case RENDERPATH_GL20:
5130 case RENDERPATH_GLES2:
5131 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
5133 case RENDERPATH_D3D9:
5135 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
5138 case RENDERPATH_D3D10:
5139 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5141 case RENDERPATH_D3D11:
5142 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5144 case RENDERPATH_SOFT:
5145 DPSOFTRAST_BlendSubtract(true);
5149 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5150 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);
5151 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5154 switch(vid.renderpath)
5156 case RENDERPATH_GL11:
5157 case RENDERPATH_GL13:
5158 case RENDERPATH_GL20:
5159 case RENDERPATH_GLES2:
5160 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
5162 case RENDERPATH_D3D9:
5164 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
5167 case RENDERPATH_D3D10:
5168 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5170 case RENDERPATH_D3D11:
5171 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5173 case RENDERPATH_SOFT:
5174 DPSOFTRAST_BlendSubtract(false);
5181 void R_Shadow_DrawCoronas(void)
5184 qboolean usequery = false;
5189 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
5191 if (r_waterstate.renderingscene)
5193 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5194 R_EntityMatrix(&identitymatrix);
5196 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5198 // check occlusion of coronas
5199 // use GL_ARB_occlusion_query if available
5200 // otherwise use raytraces
5202 switch (vid.renderpath)
5204 case RENDERPATH_GL11:
5205 case RENDERPATH_GL13:
5206 case RENDERPATH_GL20:
5207 case RENDERPATH_GLES2:
5208 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
5211 GL_ColorMask(0,0,0,0);
5212 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
5213 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
5216 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
5217 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
5219 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
5222 RSurf_ActiveWorldEntity();
5223 GL_BlendFunc(GL_ONE, GL_ZERO);
5224 GL_CullFace(GL_NONE);
5225 GL_DepthMask(false);
5226 GL_DepthRange(0, 1);
5227 GL_PolygonOffset(0, 0);
5229 R_Mesh_ResetTextureState();
5230 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
5233 case RENDERPATH_D3D9:
5235 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5237 case RENDERPATH_D3D10:
5238 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5240 case RENDERPATH_D3D11:
5241 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5243 case RENDERPATH_SOFT:
5245 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5248 for (lightindex = 0;lightindex < range;lightindex++)
5250 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5253 rtlight = &light->rtlight;
5254 rtlight->corona_visibility = 0;
5255 rtlight->corona_queryindex_visiblepixels = 0;
5256 rtlight->corona_queryindex_allpixels = 0;
5257 if (!(rtlight->flags & flag))
5259 if (rtlight->corona <= 0)
5261 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
5263 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5265 for (i = 0;i < r_refdef.scene.numlights;i++)
5267 rtlight = r_refdef.scene.lights[i];
5268 rtlight->corona_visibility = 0;
5269 rtlight->corona_queryindex_visiblepixels = 0;
5270 rtlight->corona_queryindex_allpixels = 0;
5271 if (!(rtlight->flags & flag))
5273 if (rtlight->corona <= 0)
5275 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5278 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5280 // now draw the coronas using the query data for intensity info
5281 for (lightindex = 0;lightindex < range;lightindex++)
5283 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5286 rtlight = &light->rtlight;
5287 if (rtlight->corona_visibility <= 0)
5289 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5291 for (i = 0;i < r_refdef.scene.numlights;i++)
5293 rtlight = r_refdef.scene.lights[i];
5294 if (rtlight->corona_visibility <= 0)
5296 if (gl_flashblend.integer)
5297 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
5299 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5305 dlight_t *R_Shadow_NewWorldLight(void)
5307 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
5310 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)
5313 // validate parameters
5314 if (style < 0 || style >= MAX_LIGHTSTYLES)
5316 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
5322 // copy to light properties
5323 VectorCopy(origin, light->origin);
5324 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
5325 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
5326 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
5328 light->color[0] = max(color[0], 0);
5329 light->color[1] = max(color[1], 0);
5330 light->color[2] = max(color[2], 0);
5332 light->color[0] = color[0];
5333 light->color[1] = color[1];
5334 light->color[2] = color[2];
5335 light->radius = max(radius, 0);
5336 light->style = style;
5337 light->shadow = shadowenable;
5338 light->corona = corona;
5339 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
5340 light->coronasizescale = coronasizescale;
5341 light->ambientscale = ambientscale;
5342 light->diffusescale = diffusescale;
5343 light->specularscale = specularscale;
5344 light->flags = flags;
5346 // update renderable light data
5347 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
5348 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);
5351 void R_Shadow_FreeWorldLight(dlight_t *light)
5353 if (r_shadow_selectedlight == light)
5354 r_shadow_selectedlight = NULL;
5355 R_RTLight_Uncompile(&light->rtlight);
5356 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
5359 void R_Shadow_ClearWorldLights(void)
5363 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5364 for (lightindex = 0;lightindex < range;lightindex++)
5366 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5368 R_Shadow_FreeWorldLight(light);
5370 r_shadow_selectedlight = NULL;
5373 void R_Shadow_SelectLight(dlight_t *light)
5375 if (r_shadow_selectedlight)
5376 r_shadow_selectedlight->selected = false;
5377 r_shadow_selectedlight = light;
5378 if (r_shadow_selectedlight)
5379 r_shadow_selectedlight->selected = true;
5382 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5384 // this is never batched (there can be only one)
5386 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
5387 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5388 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5391 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5396 skinframe_t *skinframe;
5399 // this is never batched (due to the ent parameter changing every time)
5400 // so numsurfaces == 1 and surfacelist[0] == lightnumber
5401 const dlight_t *light = (dlight_t *)ent;
5404 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
5407 VectorScale(light->color, intensity, spritecolor);
5408 if (VectorLength(spritecolor) < 0.1732f)
5409 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
5410 if (VectorLength(spritecolor) > 1.0f)
5411 VectorNormalize(spritecolor);
5413 // draw light sprite
5414 if (light->cubemapname[0] && !light->shadow)
5415 skinframe = r_editlights_sprcubemapnoshadowlight;
5416 else if (light->cubemapname[0])
5417 skinframe = r_editlights_sprcubemaplight;
5418 else if (!light->shadow)
5419 skinframe = r_editlights_sprnoshadowlight;
5421 skinframe = r_editlights_sprlight;
5423 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);
5424 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5426 // draw selection sprite if light is selected
5427 if (light->selected)
5429 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5430 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5431 // VorteX todo: add normalmode/realtime mode light overlay sprites?
5435 void R_Shadow_DrawLightSprites(void)
5439 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5440 for (lightindex = 0;lightindex < range;lightindex++)
5442 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5444 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
5446 if (!r_editlights_lockcursor)
5447 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
5450 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
5455 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
5456 if (lightindex >= range)
5458 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5461 rtlight = &light->rtlight;
5462 //if (!(rtlight->flags & flag))
5464 VectorCopy(rtlight->shadoworigin, origin);
5465 *radius = rtlight->radius;
5466 VectorCopy(rtlight->color, color);
5470 void R_Shadow_SelectLightInView(void)
5472 float bestrating, rating, temp[3];
5476 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5480 if (r_editlights_lockcursor)
5482 for (lightindex = 0;lightindex < range;lightindex++)
5484 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5487 VectorSubtract(light->origin, r_refdef.view.origin, temp);
5488 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
5491 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
5492 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
5494 bestrating = rating;
5499 R_Shadow_SelectLight(best);
5502 void R_Shadow_LoadWorldLights(void)
5504 int n, a, style, shadow, flags;
5505 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
5506 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
5507 if (cl.worldmodel == NULL)
5509 Con_Print("No map loaded.\n");
5512 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5513 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5523 for (;COM_Parse(t, true) && strcmp(
5524 if (COM_Parse(t, true))
5526 if (com_token[0] == '!')
5529 origin[0] = atof(com_token+1);
5532 origin[0] = atof(com_token);
5537 while (*s && *s != '\n' && *s != '\r')
5543 // check for modifier flags
5550 #if _MSC_VER >= 1400
5551 #define sscanf sscanf_s
5553 cubemapname[sizeof(cubemapname)-1] = 0;
5554 #if MAX_QPATH != 128
5555 #error update this code if MAX_QPATH changes
5557 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
5558 #if _MSC_VER >= 1400
5559 , sizeof(cubemapname)
5561 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5564 flags = LIGHTFLAG_REALTIMEMODE;
5572 coronasizescale = 0.25f;
5574 VectorClear(angles);
5577 if (a < 9 || !strcmp(cubemapname, "\"\""))
5579 // remove quotes on cubemapname
5580 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5583 namelen = strlen(cubemapname) - 2;
5584 memmove(cubemapname, cubemapname + 1, namelen);
5585 cubemapname[namelen] = '\0';
5589 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);
5592 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5600 Con_Printf("invalid rtlights file \"%s\"\n", name);
5601 Mem_Free(lightsstring);
5605 void R_Shadow_SaveWorldLights(void)
5609 size_t bufchars, bufmaxchars;
5611 char name[MAX_QPATH];
5612 char line[MAX_INPUTLINE];
5613 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5614 // I hate lines which are 3 times my screen size :( --blub
5617 if (cl.worldmodel == NULL)
5619 Con_Print("No map loaded.\n");
5622 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5623 bufchars = bufmaxchars = 0;
5625 for (lightindex = 0;lightindex < range;lightindex++)
5627 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5630 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5631 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);
5632 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5633 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]);
5635 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);
5636 if (bufchars + strlen(line) > bufmaxchars)
5638 bufmaxchars = bufchars + strlen(line) + 2048;
5640 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5644 memcpy(buf, oldbuf, bufchars);
5650 memcpy(buf + bufchars, line, strlen(line));
5651 bufchars += strlen(line);
5655 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5660 void R_Shadow_LoadLightsFile(void)
5663 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5664 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5665 if (cl.worldmodel == NULL)
5667 Con_Print("No map loaded.\n");
5670 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5671 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5679 while (*s && *s != '\n' && *s != '\r')
5685 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);
5689 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);
5692 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5693 radius = bound(15, radius, 4096);
5694 VectorScale(color, (2.0f / (8388608.0f)), color);
5695 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5703 Con_Printf("invalid lights file \"%s\"\n", name);
5704 Mem_Free(lightsstring);
5708 // tyrlite/hmap2 light types in the delay field
5709 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5711 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5723 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5724 char key[256], value[MAX_INPUTLINE];
5726 if (cl.worldmodel == NULL)
5728 Con_Print("No map loaded.\n");
5731 // try to load a .ent file first
5732 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5733 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5734 // and if that is not found, fall back to the bsp file entity string
5736 data = cl.worldmodel->brush.entities;
5739 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5741 type = LIGHTTYPE_MINUSX;
5742 origin[0] = origin[1] = origin[2] = 0;
5743 originhack[0] = originhack[1] = originhack[2] = 0;
5744 angles[0] = angles[1] = angles[2] = 0;
5745 color[0] = color[1] = color[2] = 1;
5746 light[0] = light[1] = light[2] = 1;light[3] = 300;
5747 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5757 if (!COM_ParseToken_Simple(&data, false, false))
5759 if (com_token[0] == '}')
5760 break; // end of entity
5761 if (com_token[0] == '_')
5762 strlcpy(key, com_token + 1, sizeof(key));
5764 strlcpy(key, com_token, sizeof(key));
5765 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5766 key[strlen(key)-1] = 0;
5767 if (!COM_ParseToken_Simple(&data, false, false))
5769 strlcpy(value, com_token, sizeof(value));
5771 // now that we have the key pair worked out...
5772 if (!strcmp("light", key))
5774 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5778 light[0] = vec[0] * (1.0f / 256.0f);
5779 light[1] = vec[0] * (1.0f / 256.0f);
5780 light[2] = vec[0] * (1.0f / 256.0f);
5786 light[0] = vec[0] * (1.0f / 255.0f);
5787 light[1] = vec[1] * (1.0f / 255.0f);
5788 light[2] = vec[2] * (1.0f / 255.0f);
5792 else if (!strcmp("delay", key))
5794 else if (!strcmp("origin", key))
5795 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5796 else if (!strcmp("angle", key))
5797 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5798 else if (!strcmp("angles", key))
5799 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5800 else if (!strcmp("color", key))
5801 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5802 else if (!strcmp("wait", key))
5803 fadescale = atof(value);
5804 else if (!strcmp("classname", key))
5806 if (!strncmp(value, "light", 5))
5809 if (!strcmp(value, "light_fluoro"))
5814 overridecolor[0] = 1;
5815 overridecolor[1] = 1;
5816 overridecolor[2] = 1;
5818 if (!strcmp(value, "light_fluorospark"))
5823 overridecolor[0] = 1;
5824 overridecolor[1] = 1;
5825 overridecolor[2] = 1;
5827 if (!strcmp(value, "light_globe"))
5832 overridecolor[0] = 1;
5833 overridecolor[1] = 0.8;
5834 overridecolor[2] = 0.4;
5836 if (!strcmp(value, "light_flame_large_yellow"))
5841 overridecolor[0] = 1;
5842 overridecolor[1] = 0.5;
5843 overridecolor[2] = 0.1;
5845 if (!strcmp(value, "light_flame_small_yellow"))
5850 overridecolor[0] = 1;
5851 overridecolor[1] = 0.5;
5852 overridecolor[2] = 0.1;
5854 if (!strcmp(value, "light_torch_small_white"))
5859 overridecolor[0] = 1;
5860 overridecolor[1] = 0.5;
5861 overridecolor[2] = 0.1;
5863 if (!strcmp(value, "light_torch_small_walltorch"))
5868 overridecolor[0] = 1;
5869 overridecolor[1] = 0.5;
5870 overridecolor[2] = 0.1;
5874 else if (!strcmp("style", key))
5875 style = atoi(value);
5876 else if (!strcmp("skin", key))
5877 skin = (int)atof(value);
5878 else if (!strcmp("pflags", key))
5879 pflags = (int)atof(value);
5880 //else if (!strcmp("effects", key))
5881 // effects = (int)atof(value);
5882 else if (cl.worldmodel->type == mod_brushq3)
5884 if (!strcmp("scale", key))
5885 lightscale = atof(value);
5886 if (!strcmp("fade", key))
5887 fadescale = atof(value);
5892 if (lightscale <= 0)
5896 if (color[0] == color[1] && color[0] == color[2])
5898 color[0] *= overridecolor[0];
5899 color[1] *= overridecolor[1];
5900 color[2] *= overridecolor[2];
5902 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5903 color[0] = color[0] * light[0];
5904 color[1] = color[1] * light[1];
5905 color[2] = color[2] * light[2];
5908 case LIGHTTYPE_MINUSX:
5910 case LIGHTTYPE_RECIPX:
5912 VectorScale(color, (1.0f / 16.0f), color);
5914 case LIGHTTYPE_RECIPXX:
5916 VectorScale(color, (1.0f / 16.0f), color);
5919 case LIGHTTYPE_NONE:
5923 case LIGHTTYPE_MINUSXX:
5926 VectorAdd(origin, originhack, origin);
5928 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);
5931 Mem_Free(entfiledata);
5935 void R_Shadow_SetCursorLocationForView(void)
5938 vec3_t dest, endpos;
5940 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5941 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5942 if (trace.fraction < 1)
5944 dist = trace.fraction * r_editlights_cursordistance.value;
5945 push = r_editlights_cursorpushback.value;
5949 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5950 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5954 VectorClear( endpos );
5956 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5957 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5958 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5961 void R_Shadow_UpdateWorldLightSelection(void)
5963 if (r_editlights.integer)
5965 R_Shadow_SetCursorLocationForView();
5966 R_Shadow_SelectLightInView();
5969 R_Shadow_SelectLight(NULL);
5972 void R_Shadow_EditLights_Clear_f(void)
5974 R_Shadow_ClearWorldLights();
5977 void R_Shadow_EditLights_Reload_f(void)
5981 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5982 R_Shadow_ClearWorldLights();
5983 R_Shadow_LoadWorldLights();
5984 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5986 R_Shadow_LoadLightsFile();
5987 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5988 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5992 void R_Shadow_EditLights_Save_f(void)
5996 R_Shadow_SaveWorldLights();
5999 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6001 R_Shadow_ClearWorldLights();
6002 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6005 void R_Shadow_EditLights_ImportLightsFile_f(void)
6007 R_Shadow_ClearWorldLights();
6008 R_Shadow_LoadLightsFile();
6011 void R_Shadow_EditLights_Spawn_f(void)
6014 if (!r_editlights.integer)
6016 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6019 if (Cmd_Argc() != 1)
6021 Con_Print("r_editlights_spawn does not take parameters\n");
6024 color[0] = color[1] = color[2] = 1;
6025 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6028 void R_Shadow_EditLights_Edit_f(void)
6030 vec3_t origin, angles, color;
6031 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6032 int style, shadows, flags, normalmode, realtimemode;
6033 char cubemapname[MAX_INPUTLINE];
6034 if (!r_editlights.integer)
6036 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6039 if (!r_shadow_selectedlight)
6041 Con_Print("No selected light.\n");
6044 VectorCopy(r_shadow_selectedlight->origin, origin);
6045 VectorCopy(r_shadow_selectedlight->angles, angles);
6046 VectorCopy(r_shadow_selectedlight->color, color);
6047 radius = r_shadow_selectedlight->radius;
6048 style = r_shadow_selectedlight->style;
6049 if (r_shadow_selectedlight->cubemapname)
6050 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6053 shadows = r_shadow_selectedlight->shadow;
6054 corona = r_shadow_selectedlight->corona;
6055 coronasizescale = r_shadow_selectedlight->coronasizescale;
6056 ambientscale = r_shadow_selectedlight->ambientscale;
6057 diffusescale = r_shadow_selectedlight->diffusescale;
6058 specularscale = r_shadow_selectedlight->specularscale;
6059 flags = r_shadow_selectedlight->flags;
6060 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6061 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6062 if (!strcmp(Cmd_Argv(1), "origin"))
6064 if (Cmd_Argc() != 5)
6066 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6069 origin[0] = atof(Cmd_Argv(2));
6070 origin[1] = atof(Cmd_Argv(3));
6071 origin[2] = atof(Cmd_Argv(4));
6073 else if (!strcmp(Cmd_Argv(1), "originx"))
6075 if (Cmd_Argc() != 3)
6077 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6080 origin[0] = atof(Cmd_Argv(2));
6082 else if (!strcmp(Cmd_Argv(1), "originy"))
6084 if (Cmd_Argc() != 3)
6086 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6089 origin[1] = atof(Cmd_Argv(2));
6091 else if (!strcmp(Cmd_Argv(1), "originz"))
6093 if (Cmd_Argc() != 3)
6095 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6098 origin[2] = atof(Cmd_Argv(2));
6100 else if (!strcmp(Cmd_Argv(1), "move"))
6102 if (Cmd_Argc() != 5)
6104 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6107 origin[0] += atof(Cmd_Argv(2));
6108 origin[1] += atof(Cmd_Argv(3));
6109 origin[2] += atof(Cmd_Argv(4));
6111 else if (!strcmp(Cmd_Argv(1), "movex"))
6113 if (Cmd_Argc() != 3)
6115 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6118 origin[0] += atof(Cmd_Argv(2));
6120 else if (!strcmp(Cmd_Argv(1), "movey"))
6122 if (Cmd_Argc() != 3)
6124 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6127 origin[1] += atof(Cmd_Argv(2));
6129 else if (!strcmp(Cmd_Argv(1), "movez"))
6131 if (Cmd_Argc() != 3)
6133 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6136 origin[2] += atof(Cmd_Argv(2));
6138 else if (!strcmp(Cmd_Argv(1), "angles"))
6140 if (Cmd_Argc() != 5)
6142 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6145 angles[0] = atof(Cmd_Argv(2));
6146 angles[1] = atof(Cmd_Argv(3));
6147 angles[2] = atof(Cmd_Argv(4));
6149 else if (!strcmp(Cmd_Argv(1), "anglesx"))
6151 if (Cmd_Argc() != 3)
6153 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6156 angles[0] = atof(Cmd_Argv(2));
6158 else if (!strcmp(Cmd_Argv(1), "anglesy"))
6160 if (Cmd_Argc() != 3)
6162 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6165 angles[1] = atof(Cmd_Argv(2));
6167 else if (!strcmp(Cmd_Argv(1), "anglesz"))
6169 if (Cmd_Argc() != 3)
6171 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6174 angles[2] = atof(Cmd_Argv(2));
6176 else if (!strcmp(Cmd_Argv(1), "color"))
6178 if (Cmd_Argc() != 5)
6180 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
6183 color[0] = atof(Cmd_Argv(2));
6184 color[1] = atof(Cmd_Argv(3));
6185 color[2] = atof(Cmd_Argv(4));
6187 else if (!strcmp(Cmd_Argv(1), "radius"))
6189 if (Cmd_Argc() != 3)
6191 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6194 radius = atof(Cmd_Argv(2));
6196 else if (!strcmp(Cmd_Argv(1), "colorscale"))
6198 if (Cmd_Argc() == 3)
6200 double scale = atof(Cmd_Argv(2));
6207 if (Cmd_Argc() != 5)
6209 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
6212 color[0] *= atof(Cmd_Argv(2));
6213 color[1] *= atof(Cmd_Argv(3));
6214 color[2] *= atof(Cmd_Argv(4));
6217 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
6219 if (Cmd_Argc() != 3)
6221 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6224 radius *= atof(Cmd_Argv(2));
6226 else if (!strcmp(Cmd_Argv(1), "style"))
6228 if (Cmd_Argc() != 3)
6230 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6233 style = atoi(Cmd_Argv(2));
6235 else if (!strcmp(Cmd_Argv(1), "cubemap"))
6239 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6242 if (Cmd_Argc() == 3)
6243 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
6247 else if (!strcmp(Cmd_Argv(1), "shadows"))
6249 if (Cmd_Argc() != 3)
6251 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6254 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6256 else if (!strcmp(Cmd_Argv(1), "corona"))
6258 if (Cmd_Argc() != 3)
6260 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6263 corona = atof(Cmd_Argv(2));
6265 else if (!strcmp(Cmd_Argv(1), "coronasize"))
6267 if (Cmd_Argc() != 3)
6269 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6272 coronasizescale = atof(Cmd_Argv(2));
6274 else if (!strcmp(Cmd_Argv(1), "ambient"))
6276 if (Cmd_Argc() != 3)
6278 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6281 ambientscale = atof(Cmd_Argv(2));
6283 else if (!strcmp(Cmd_Argv(1), "diffuse"))
6285 if (Cmd_Argc() != 3)
6287 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6290 diffusescale = atof(Cmd_Argv(2));
6292 else if (!strcmp(Cmd_Argv(1), "specular"))
6294 if (Cmd_Argc() != 3)
6296 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6299 specularscale = atof(Cmd_Argv(2));
6301 else if (!strcmp(Cmd_Argv(1), "normalmode"))
6303 if (Cmd_Argc() != 3)
6305 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6308 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6310 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
6312 if (Cmd_Argc() != 3)
6314 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6317 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6321 Con_Print("usage: r_editlights_edit [property] [value]\n");
6322 Con_Print("Selected light's properties:\n");
6323 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6324 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6325 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6326 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
6327 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
6328 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
6329 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
6330 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
6331 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
6332 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
6333 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
6334 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
6335 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
6336 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
6339 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
6340 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6343 void R_Shadow_EditLights_EditAll_f(void)
6346 dlight_t *light, *oldselected;
6349 if (!r_editlights.integer)
6351 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
6355 oldselected = r_shadow_selectedlight;
6356 // EditLights doesn't seem to have a "remove" command or something so:
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 R_Shadow_SelectLight(light);
6364 R_Shadow_EditLights_Edit_f();
6366 // return to old selected (to not mess editing once selection is locked)
6367 R_Shadow_SelectLight(oldselected);
6370 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
6372 int lightnumber, lightcount;
6373 size_t lightindex, range;
6377 if (!r_editlights.integer)
6379 x = vid_conwidth.value - 240;
6381 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
6384 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6385 for (lightindex = 0;lightindex < range;lightindex++)
6387 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6390 if (light == r_shadow_selectedlight)
6391 lightnumber = lightindex;
6394 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;
6395 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;
6397 if (r_shadow_selectedlight == NULL)
6399 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;
6400 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;
6401 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;
6402 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;
6403 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;
6404 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;
6405 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;
6406 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;
6407 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;
6408 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;
6409 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;
6410 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;
6411 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;
6412 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;
6413 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;
6416 void R_Shadow_EditLights_ToggleShadow_f(void)
6418 if (!r_editlights.integer)
6420 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6423 if (!r_shadow_selectedlight)
6425 Con_Print("No selected light.\n");
6428 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);
6431 void R_Shadow_EditLights_ToggleCorona_f(void)
6433 if (!r_editlights.integer)
6435 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6438 if (!r_shadow_selectedlight)
6440 Con_Print("No selected light.\n");
6443 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);
6446 void R_Shadow_EditLights_Remove_f(void)
6448 if (!r_editlights.integer)
6450 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
6453 if (!r_shadow_selectedlight)
6455 Con_Print("No selected light.\n");
6458 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
6459 r_shadow_selectedlight = NULL;
6462 void R_Shadow_EditLights_Help_f(void)
6465 "Documentation on r_editlights system:\n"
6467 "r_editlights : enable/disable editing mode\n"
6468 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
6469 "r_editlights_cursorpushback : push back cursor this far from surface\n"
6470 "r_editlights_cursorpushoff : push cursor off surface this far\n"
6471 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
6472 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
6474 "r_editlights_help : this help\n"
6475 "r_editlights_clear : remove all lights\n"
6476 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
6477 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
6478 "r_editlights_save : save to .rtlights file\n"
6479 "r_editlights_spawn : create a light with default settings\n"
6480 "r_editlights_edit command : edit selected light - more documentation below\n"
6481 "r_editlights_remove : remove selected light\n"
6482 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
6483 "r_editlights_importlightentitiesfrommap : reload light entities\n"
6484 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
6486 "origin x y z : set light location\n"
6487 "originx x: set x component of light location\n"
6488 "originy y: set y component of light location\n"
6489 "originz z: set z component of light location\n"
6490 "move x y z : adjust light location\n"
6491 "movex x: adjust x component of light location\n"
6492 "movey y: adjust y component of light location\n"
6493 "movez z: adjust z component of light location\n"
6494 "angles x y z : set light angles\n"
6495 "anglesx x: set x component of light angles\n"
6496 "anglesy y: set y component of light angles\n"
6497 "anglesz z: set z component of light angles\n"
6498 "color r g b : set color of light (can be brighter than 1 1 1)\n"
6499 "radius radius : set radius (size) of light\n"
6500 "colorscale grey : multiply color of light (1 does nothing)\n"
6501 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
6502 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
6503 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
6504 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
6505 "cubemap basename : set filter cubemap of light (not yet supported)\n"
6506 "shadows 1/0 : turn on/off shadows\n"
6507 "corona n : set corona intensity\n"
6508 "coronasize n : set corona size (0-1)\n"
6509 "ambient n : set ambient intensity (0-1)\n"
6510 "diffuse n : set diffuse intensity (0-1)\n"
6511 "specular n : set specular intensity (0-1)\n"
6512 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6513 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6514 "<nothing> : print light properties to console\n"
6518 void R_Shadow_EditLights_CopyInfo_f(void)
6520 if (!r_editlights.integer)
6522 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
6525 if (!r_shadow_selectedlight)
6527 Con_Print("No selected light.\n");
6530 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6531 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6532 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6533 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6534 if (r_shadow_selectedlight->cubemapname)
6535 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6537 r_shadow_bufferlight.cubemapname[0] = 0;
6538 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6539 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6540 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6541 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6542 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6543 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6544 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6547 void R_Shadow_EditLights_PasteInfo_f(void)
6549 if (!r_editlights.integer)
6551 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6554 if (!r_shadow_selectedlight)
6556 Con_Print("No selected light.\n");
6559 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);
6562 void R_Shadow_EditLights_Lock_f(void)
6564 if (!r_editlights.integer)
6566 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6569 if (r_editlights_lockcursor)
6571 r_editlights_lockcursor = false;
6574 if (!r_shadow_selectedlight)
6576 Con_Print("No selected light to lock on.\n");
6579 r_editlights_lockcursor = true;
6582 void R_Shadow_EditLights_Init(void)
6584 Cvar_RegisterVariable(&r_editlights);
6585 Cvar_RegisterVariable(&r_editlights_cursordistance);
6586 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6587 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6588 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6589 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6590 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6591 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6592 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)");
6593 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6594 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6595 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6596 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)");
6597 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6598 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6599 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6600 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6601 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6602 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6603 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)");
6604 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6610 =============================================================================
6614 =============================================================================
6617 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
6619 int i, numlights, flag;
6622 float relativepoint[3];
6631 if (r_fullbright.integer)
6633 VectorSet(ambient, 1, 1, 1);
6634 VectorClear(diffuse);
6635 VectorClear(lightdir);
6639 if (flags & LP_LIGHTMAP)
6641 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6642 VectorClear(diffuse);
6643 VectorClear(lightdir);
6644 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6645 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
6649 memset(sample, 0, sizeof(sample));
6650 VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6652 if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6655 VectorClear(tempambient);
6657 VectorClear(relativepoint);
6658 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6659 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
6660 VectorScale(color, r_refdef.lightmapintensity, color);
6661 VectorAdd(sample, tempambient, sample);
6662 VectorMA(sample , 0.5f , color, sample );
6663 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6664 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6665 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6666 // calculate a weighted average light direction as well
6667 intensity = VectorLength(color);
6668 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6671 if (flags & LP_RTWORLD)
6673 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6674 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6675 for (i = 0; i < numlights; i++)
6677 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6680 light = &dlight->rtlight;
6681 if (!(light->flags & flag))
6684 lightradius2 = light->radius * light->radius;
6685 VectorSubtract(light->shadoworigin, p, relativepoint);
6686 dist2 = VectorLength2(relativepoint);
6687 if (dist2 >= lightradius2)
6689 dist = sqrt(dist2) / light->radius;
6690 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6691 if (intensity <= 0.0f)
6693 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
6695 // scale down intensity to add to both ambient and diffuse
6696 //intensity *= 0.5f;
6697 VectorNormalize(relativepoint);
6698 VectorScale(light->currentcolor, intensity, color);
6699 VectorMA(sample , 0.5f , color, sample );
6700 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6701 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6702 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6703 // calculate a weighted average light direction as well
6704 intensity *= VectorLength(color);
6705 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6709 if (flags & LP_DYNLIGHT)
6712 for (i = 0;i < r_refdef.scene.numlights;i++)
6714 light = r_refdef.scene.lights[i];
6716 lightradius2 = light->radius * light->radius;
6717 VectorSubtract(light->shadoworigin, p, relativepoint);
6718 dist2 = VectorLength2(relativepoint);
6719 if (dist2 >= lightradius2)
6721 dist = sqrt(dist2) / light->radius;
6722 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6723 if (intensity <= 0.0f)
6725 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
6727 // scale down intensity to add to both ambient and diffuse
6728 //intensity *= 0.5f;
6729 VectorNormalize(relativepoint);
6730 VectorScale(light->currentcolor, intensity, color);
6731 VectorMA(sample , 0.5f , color, sample );
6732 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6733 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6734 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6735 // calculate a weighted average light direction as well
6736 intensity *= VectorLength(color);
6737 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6741 // calculate the direction we'll use to reduce the sample to a directional light source
6742 VectorCopy(sample + 12, dir);
6743 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
6744 VectorNormalize(dir);
6745 // extract the diffuse color along the chosen direction and scale it
6746 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
6747 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
6748 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
6749 // subtract some of diffuse from ambient
6750 VectorMA(sample, -0.333f, diffuse, ambient);
6751 // store the normalized lightdir
6752 VectorCopy(dir, lightdir);