3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however. Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light. This technique is used heavily in many games (Doom3 does not support
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
142 #include "dpsoftrast.h"
146 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
149 static void R_Shadow_EditLights_Init(void);
151 typedef enum r_shadow_rendermode_e
153 R_SHADOW_RENDERMODE_NONE,
154 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
155 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
156 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
157 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
158 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
159 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
160 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
161 R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN,
162 R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN,
163 R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN,
164 R_SHADOW_RENDERMODE_LIGHT_GLSL,
165 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
166 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
167 R_SHADOW_RENDERMODE_SHADOWMAP2D
169 r_shadow_rendermode_t;
171 typedef enum r_shadow_shadowmode_e
173 R_SHADOW_SHADOWMODE_STENCIL,
174 R_SHADOW_SHADOWMODE_SHADOWMAP2D
176 r_shadow_shadowmode_t;
178 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
180 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
181 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
182 int r_shadow_scenemaxlights;
183 int r_shadow_scenenumlights;
184 rtlight_t **r_shadow_scenelightlist; // includes both static lights and dlights, as filtered by appropriate flags
185 qboolean r_shadow_usingshadowmap2d;
186 qboolean r_shadow_usingshadowmaportho;
187 int r_shadow_shadowmapside;
188 float r_shadow_lightshadowmap_texturescale[4]; // xy = scale, zw = offset
189 float r_shadow_lightshadowmap_parameters[4]; // x = frustum width in pixels (excludes border), y = z scale, z = size of viewport, w = z center
190 float r_shadow_modelshadowmap_texturescale[4]; // xy = scale, zw = offset
191 float r_shadow_modelshadowmap_parameters[4]; // xyz = scale, w = shadow brightness
193 int r_shadow_drawbuffer;
194 int r_shadow_readbuffer;
196 int r_shadow_cullface_front, r_shadow_cullface_back;
197 GLuint r_shadow_fbo2d;
198 r_shadow_shadowmode_t r_shadow_shadowmode;
199 int r_shadow_shadowmapfilterquality;
200 int r_shadow_shadowmapdepthbits;
201 int r_shadow_shadowmapmaxsize;
202 int r_shadow_shadowmaptexturesize;
203 qboolean r_shadow_shadowmapvsdct;
204 qboolean r_shadow_shadowmapsampler;
205 qboolean r_shadow_shadowmapshadowsampler;
206 int r_shadow_shadowmappcf;
207 int r_shadow_shadowmapborder;
208 matrix4x4_t r_shadow_shadowmapmatrix;
209 int r_shadow_lightscissor[4];
210 qboolean r_shadow_usingdeferredprepass;
211 qboolean r_shadow_shadowmapdepthtexture;
212 mod_alloclightmap_state_t r_shadow_shadowmapatlas_state;
213 int r_shadow_shadowmapatlas_modelshadows_x;
214 int r_shadow_shadowmapatlas_modelshadows_y;
215 int r_shadow_shadowmapatlas_modelshadows_size;
216 int maxshadowtriangles;
219 int maxshadowvertices;
220 float *shadowvertex3f;
230 unsigned char *shadowsides;
231 int *shadowsideslist;
238 int r_shadow_buffer_numleafpvsbytes;
239 unsigned char *r_shadow_buffer_visitingleafpvs;
240 unsigned char *r_shadow_buffer_leafpvs;
241 int *r_shadow_buffer_leaflist;
243 int r_shadow_buffer_numsurfacepvsbytes;
244 unsigned char *r_shadow_buffer_surfacepvs;
245 int *r_shadow_buffer_surfacelist;
246 unsigned char *r_shadow_buffer_surfacesides;
248 int r_shadow_buffer_numshadowtrispvsbytes;
249 unsigned char *r_shadow_buffer_shadowtrispvs;
250 int r_shadow_buffer_numlighttrispvsbytes;
251 unsigned char *r_shadow_buffer_lighttrispvs;
253 rtexturepool_t *r_shadow_texturepool;
254 rtexture_t *r_shadow_attenuationgradienttexture;
255 rtexture_t *r_shadow_attenuation2dtexture;
256 rtexture_t *r_shadow_attenuation3dtexture;
257 skinframe_t *r_shadow_lightcorona;
258 rtexture_t *r_shadow_shadowmap2ddepthbuffer;
259 rtexture_t *r_shadow_shadowmap2ddepthtexture;
260 rtexture_t *r_shadow_shadowmapvsdcttexture;
262 GLuint r_shadow_prepassgeometryfbo;
263 GLuint r_shadow_prepasslightingdiffusespecularfbo;
264 GLuint r_shadow_prepasslightingdiffusefbo;
265 int r_shadow_prepass_width;
266 int r_shadow_prepass_height;
267 rtexture_t *r_shadow_prepassgeometrydepthbuffer;
268 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
269 rtexture_t *r_shadow_prepasslightingdiffusetexture;
270 rtexture_t *r_shadow_prepasslightingspeculartexture;
272 // keep track of the provided framebuffer info
273 static int r_shadow_fb_fbo;
274 static rtexture_t *r_shadow_fb_depthtexture;
275 static rtexture_t *r_shadow_fb_colortexture;
277 // lights are reloaded when this changes
278 char r_shadow_mapname[MAX_QPATH];
280 // buffer for doing corona fading
281 unsigned int r_shadow_occlusion_buf = 0;
283 // used only for light filters (cubemaps)
284 rtexturepool_t *r_shadow_filters_texturepool;
286 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"};
287 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"};
288 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
289 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"};
290 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)"};
291 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
292 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)"};
293 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"};
294 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
295 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
296 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
297 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
298 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
299 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
300 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
301 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
302 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
303 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)"};
304 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
305 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
306 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
307 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
308 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)"};
309 cvar_t r_shadow_realtime_world_importlightentitiesfrommap = {0, "r_shadow_realtime_world_importlightentitiesfrommap", "1", "load lights from .ent file or map entities at startup if no .rtlights or .lights file is present (if set to 2, always use the .ent or map entities)"};
310 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"};
311 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
312 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
313 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"};
314 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)"};
315 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
316 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)"};
317 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "1", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes"};
318 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)"};
319 cvar_t r_shadow_shadowmapping_useshadowsampler = {CVAR_SAVE, "r_shadow_shadowmapping_useshadowsampler", "1", "whether to use sampler2DShadow if available"};
320 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
321 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
322 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "limit of shadowmap side size - must be at least r_shadow_shadowmapping_bordersize+2"};
323 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "limit of shadowmap side size - can not be more than 1/8th of atlassize because lights store 6 sides (2x3 grid) and sometimes 12 sides (4x3 grid for shadows from EF_NOSELFSHADOW entities) and there are multiple lights..."};
324 cvar_t r_shadow_shadowmapping_texturesize = { CVAR_SAVE, "r_shadow_shadowmapping_texturesize", "8192", "size of shadowmap atlas texture - all shadowmaps are packed into this texture at frame start"};
325 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"};
326 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
327 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
328 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
329 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
330 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
331 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
332 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
333 cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
334 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
335 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)"};
336 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)"};
337 cvar_t r_shadow_bouncegrid = {CVAR_SAVE, "r_shadow_bouncegrid", "0", "perform particle tracing for indirect lighting (Global Illumination / radiosity) using a 3D texture covering the scene, only active on levels with realtime lights active (r_shadow_realtime_world is usually required for these)"};
338 cvar_t r_shadow_bouncegrid_blur = {CVAR_SAVE, "r_shadow_bouncegrid_blur", "0", "apply a 1-radius blur on bouncegrid to denoise it and deal with boundary issues with surfaces"};
339 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"};
340 cvar_t r_shadow_bouncegrid_dynamic_bounceminimumintensity = { CVAR_SAVE, "r_shadow_bouncegrid_dynamic_bounceminimumintensity", "0.05", "stop bouncing once intensity drops below this fraction of the original particle color" };
341 cvar_t r_shadow_bouncegrid_dynamic_culllightpaths = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_culllightpaths", "1", "skip accumulating light in the bouncegrid texture where the light paths are out of view (dynamic mode only)"};
342 cvar_t r_shadow_bouncegrid_dynamic_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_directionalshading", "0", "use diffuse shading rather than ambient, 3D texture becomes 8x as many pixels to hold the additional data"};
343 cvar_t r_shadow_bouncegrid_dynamic_dlightparticlemultiplier = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_dlightparticlemultiplier", "1", "if set to a high value like 16 this can make dlights look great, but 0 is recommended for performance reasons"};
344 cvar_t r_shadow_bouncegrid_dynamic_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
345 cvar_t r_shadow_bouncegrid_dynamic_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_lightradiusscale", "2", "particles stop at this fraction of light radius (can be more than 1)"};
346 cvar_t r_shadow_bouncegrid_dynamic_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_maxbounce", "2", "maximum number of bounces for a particle (minimum is 0)"};
347 cvar_t r_shadow_bouncegrid_dynamic_maxphotons = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_maxphotons", "25000", "upper bound on photons to shoot per update, divided proportionately between lights - normally the number of photons is calculated by energyperphoton"};
348 cvar_t r_shadow_bouncegrid_dynamic_quality = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_quality", "1", "amount of photons that should be fired (this is multiplied by spacing^2 to make it adaptive with spacing changes)"};
349 cvar_t r_shadow_bouncegrid_dynamic_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_spacing", "64", "unit size of bouncegrid pixel"};
350 cvar_t r_shadow_bouncegrid_dynamic_updateinterval = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_updateinterval", "0", "update bouncegrid texture once per this many seconds, useful values are 0, 0.05, or 1000000"};
351 cvar_t r_shadow_bouncegrid_dynamic_x = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_x", "64", "maximum texture size of bouncegrid on X axis"};
352 cvar_t r_shadow_bouncegrid_dynamic_y = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_y", "64", "maximum texture size of bouncegrid on Y axis"};
353 cvar_t r_shadow_bouncegrid_dynamic_z = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_z", "32", "maximum texture size of bouncegrid on Z axis"};
354 cvar_t r_shadow_bouncegrid_floatcolors = {CVAR_SAVE, "r_shadow_bouncegrid_floatcolors", "1", "upload texture as RGBA16F (or RGBA32F when set to 2) rather than RGBA8 format - this gives more dynamic range and accuracy"};
355 cvar_t r_shadow_bouncegrid_includedirectlighting = {CVAR_SAVE, "r_shadow_bouncegrid_includedirectlighting", "0", "allows direct lighting to be recorded, not just indirect (gives an effect somewhat like r_shadow_realtime_world_lightmaps)"};
356 cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
357 cvar_t r_shadow_bouncegrid_lightpathsize_conespread = {CVAR_SAVE, "r_shadow_bouncegrid_lightpathsize_conespread", "0.015625", "increase lightpathsize over distance at this rate per grid cell"};
358 cvar_t r_shadow_bouncegrid_lightpathsize_initial = {CVAR_SAVE, "r_shadow_bouncegrid_lightpathsize_initial", "0.5", "width (in grid cells) of the light path for accumulation of light in the bouncegrid texture"};
359 cvar_t r_shadow_bouncegrid_normalizevectors = { CVAR_SAVE, "r_shadow_bouncegrid_normalizevectors", "1", "normalize random vectors (otherwise their length can vary, which dims the lighting further from the light)" };
360 cvar_t r_shadow_bouncegrid_particlebounceintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particlebounceintensity", "2", "amount of energy carried over after each bounce, this is a multiplier of texture color and the result is clamped to 1 or less, to prevent adding energy on each bounce"};
361 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "0.25", "brightness of particles contributing to bouncegrid texture"};
362 cvar_t r_shadow_bouncegrid_rng_seed = { CVAR_SAVE, "r_shadow_bouncegrid_rng_seed", "0", "0+ = use this number as RNG seed, -1 = use time instead for disco-like craziness in dynamic mode" };
363 cvar_t r_shadow_bouncegrid_rng_type = { CVAR_SAVE, "r_shadow_bouncegrid_rng_type", "0", "0 = Lehmer 128bit RNG (slow but high quality), 1 = lhcheeserand 32bit RNG (quick)" };
364 cvar_t r_shadow_bouncegrid_sortlightpaths = {CVAR_SAVE, "r_shadow_bouncegrid_sortlightpaths", "1", "sort light paths before accumulating them into the bouncegrid texture, this reduces cpu cache misses"};
365 cvar_t r_shadow_bouncegrid_static = {CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
366 cvar_t r_shadow_bouncegrid_static_bounceminimumintensity = { CVAR_SAVE, "r_shadow_bouncegrid_static_bounceminimumintensity", "0.01", "stop bouncing once intensity drops below this fraction of the original particle color" };
367 cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
368 cvar_t r_shadow_bouncegrid_static_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_static_lightradiusscale", "2", "particles stop at this fraction of light radius (can be more than 1) when in static mode"};
369 cvar_t r_shadow_bouncegrid_static_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_static_maxbounce", "5", "maximum number of bounces for a particle (minimum is 0) in static mode"};
370 cvar_t r_shadow_bouncegrid_static_maxphotons = {CVAR_SAVE, "r_shadow_bouncegrid_static_maxphotons", "250000", "upper bound on photons in static mode"};
371 cvar_t r_shadow_bouncegrid_static_quality = { CVAR_SAVE, "r_shadow_bouncegrid_static_quality", "16", "amount of photons that should be fired (this is multiplied by spacing^2 to make it adaptive with spacing changes)" };
372 cvar_t r_shadow_bouncegrid_static_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_static_spacing", "64", "unit size of bouncegrid pixel when in static mode"};
373 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
374 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"};
375 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "0", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility) - bad performance (synchronous rendering) - worse on multi-gpu!"};
376 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
377 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
378 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
379 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
380 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
381 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
382 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
383 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
384 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
385 cvar_t r_editlights_drawproperties = {0, "r_editlights_drawproperties", "1", "draw properties of currently selected light"};
386 cvar_t r_editlights_current_origin = {0, "r_editlights_current_origin", "0 0 0", "origin of selected light"};
387 cvar_t r_editlights_current_angles = {0, "r_editlights_current_angles", "0 0 0", "angles of selected light"};
388 cvar_t r_editlights_current_color = {0, "r_editlights_current_color", "1 1 1", "color of selected light"};
389 cvar_t r_editlights_current_radius = {0, "r_editlights_current_radius", "0", "radius of selected light"};
390 cvar_t r_editlights_current_corona = {0, "r_editlights_current_corona", "0", "corona intensity of selected light"};
391 cvar_t r_editlights_current_coronasize = {0, "r_editlights_current_coronasize", "0", "corona size of selected light"};
392 cvar_t r_editlights_current_style = {0, "r_editlights_current_style", "0", "style of selected light"};
393 cvar_t r_editlights_current_shadows = {0, "r_editlights_current_shadows", "0", "shadows flag of selected light"};
394 cvar_t r_editlights_current_cubemap = {0, "r_editlights_current_cubemap", "0", "cubemap of selected light"};
395 cvar_t r_editlights_current_ambient = {0, "r_editlights_current_ambient", "0", "ambient intensity of selected light"};
396 cvar_t r_editlights_current_diffuse = {0, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"};
397 cvar_t r_editlights_current_specular = {0, "r_editlights_current_specular", "1", "specular intensity of selected light"};
398 cvar_t r_editlights_current_normalmode = {0, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"};
399 cvar_t r_editlights_current_realtimemode = {0, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"};
401 r_shadow_bouncegrid_state_t r_shadow_bouncegrid_state;
403 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
404 #define ATTENTABLESIZE 256
405 // 1D gradient, 2D circle and 3D sphere attenuation textures
406 #define ATTEN1DSIZE 32
407 #define ATTEN2DSIZE 64
408 #define ATTEN3DSIZE 32
410 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
411 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
412 static float r_shadow_attentable[ATTENTABLESIZE+1];
414 rtlight_t *r_shadow_compilingrtlight;
415 static memexpandablearray_t r_shadow_worldlightsarray;
416 dlight_t *r_shadow_selectedlight;
417 dlight_t r_shadow_bufferlight;
418 vec3_t r_editlights_cursorlocation;
419 qboolean r_editlights_lockcursor;
421 extern int con_vislines;
423 void R_Shadow_UncompileWorldLights(void);
424 void R_Shadow_ClearWorldLights(void);
425 void R_Shadow_SaveWorldLights(void);
426 void R_Shadow_LoadWorldLights(void);
427 void R_Shadow_LoadLightsFile(void);
428 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
429 void R_Shadow_EditLights_Reload_f(void);
430 void R_Shadow_ValidateCvars(void);
431 static void R_Shadow_MakeTextures(void);
433 #define EDLIGHTSPRSIZE 8
434 skinframe_t *r_editlights_sprcursor;
435 skinframe_t *r_editlights_sprlight;
436 skinframe_t *r_editlights_sprnoshadowlight;
437 skinframe_t *r_editlights_sprcubemaplight;
438 skinframe_t *r_editlights_sprcubemapnoshadowlight;
439 skinframe_t *r_editlights_sprselection;
441 static void R_Shadow_DrawModelShadowMaps(void);
442 static void R_Shadow_MakeShadowMap(int texturesize);
443 static void R_Shadow_MakeVSDCT(void);
444 static void R_Shadow_SetShadowMode(void)
446 r_shadow_shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
447 r_shadow_shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
448 r_shadow_shadowmapmaxsize = bound(r_shadow_shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, r_shadow_shadowmaptexturesize / 8);
449 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
450 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
451 r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
452 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
453 r_shadow_shadowmapsampler = false;
454 r_shadow_shadowmappcf = 0;
455 r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
456 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
457 Mod_AllocLightmap_Init(&r_shadow_shadowmapatlas_state, r_main_mempool, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize);
458 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
460 switch(vid.renderpath)
462 case RENDERPATH_GL20:
463 if(r_shadow_shadowmapfilterquality < 0)
465 if (!r_fb.usedepthtextures)
466 r_shadow_shadowmappcf = 1;
467 else if((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && vid.support.arb_shadow && r_shadow_shadowmapshadowsampler)
469 r_shadow_shadowmapsampler = true;
470 r_shadow_shadowmappcf = 1;
472 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
473 r_shadow_shadowmappcf = 1;
474 else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa"))
475 r_shadow_shadowmappcf = 1;
477 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
481 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
482 switch (r_shadow_shadowmapfilterquality)
487 r_shadow_shadowmappcf = 1;
490 r_shadow_shadowmappcf = 1;
493 r_shadow_shadowmappcf = 2;
497 if (!r_fb.usedepthtextures)
498 r_shadow_shadowmapsampler = false;
499 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
501 case RENDERPATH_D3D9:
502 case RENDERPATH_D3D10:
503 case RENDERPATH_D3D11:
504 case RENDERPATH_SOFT:
505 r_shadow_shadowmapsampler = false;
506 r_shadow_shadowmappcf = 1;
507 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
509 case RENDERPATH_GL11:
510 case RENDERPATH_GL13:
511 case RENDERPATH_GLES1:
512 case RENDERPATH_GLES2:
517 if(R_CompileShader_CheckStaticParms())
521 qboolean R_Shadow_ShadowMappingEnabled(void)
523 switch (r_shadow_shadowmode)
525 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
532 static void R_Shadow_FreeShadowMaps(void)
534 Mod_AllocLightmap_Free(&r_shadow_shadowmapatlas_state);
536 R_Shadow_SetShadowMode();
538 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
542 if (r_shadow_shadowmap2ddepthtexture)
543 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
544 r_shadow_shadowmap2ddepthtexture = NULL;
546 if (r_shadow_shadowmap2ddepthbuffer)
547 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
548 r_shadow_shadowmap2ddepthbuffer = NULL;
550 if (r_shadow_shadowmapvsdcttexture)
551 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
552 r_shadow_shadowmapvsdcttexture = NULL;
555 static void r_shadow_start(void)
557 // allocate vertex processing arrays
558 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
559 r_shadow_attenuationgradienttexture = NULL;
560 r_shadow_attenuation2dtexture = NULL;
561 r_shadow_attenuation3dtexture = NULL;
562 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
563 r_shadow_shadowmap2ddepthtexture = NULL;
564 r_shadow_shadowmap2ddepthbuffer = NULL;
565 r_shadow_shadowmapvsdcttexture = NULL;
566 r_shadow_shadowmapmaxsize = 0;
567 r_shadow_shadowmaptexturesize = 0;
568 r_shadow_shadowmapfilterquality = -1;
569 r_shadow_shadowmapdepthbits = 0;
570 r_shadow_shadowmapvsdct = false;
571 r_shadow_shadowmapsampler = false;
572 r_shadow_shadowmappcf = 0;
575 R_Shadow_FreeShadowMaps();
577 r_shadow_texturepool = NULL;
578 r_shadow_filters_texturepool = NULL;
579 R_Shadow_ValidateCvars();
580 R_Shadow_MakeTextures();
581 r_shadow_scenemaxlights = 0;
582 r_shadow_scenenumlights = 0;
583 r_shadow_scenelightlist = NULL;
584 maxshadowtriangles = 0;
585 shadowelements = NULL;
586 maxshadowvertices = 0;
587 shadowvertex3f = NULL;
595 shadowmarklist = NULL;
600 shadowsideslist = NULL;
601 r_shadow_buffer_numleafpvsbytes = 0;
602 r_shadow_buffer_visitingleafpvs = NULL;
603 r_shadow_buffer_leafpvs = NULL;
604 r_shadow_buffer_leaflist = NULL;
605 r_shadow_buffer_numsurfacepvsbytes = 0;
606 r_shadow_buffer_surfacepvs = NULL;
607 r_shadow_buffer_surfacelist = NULL;
608 r_shadow_buffer_surfacesides = NULL;
609 r_shadow_buffer_numshadowtrispvsbytes = 0;
610 r_shadow_buffer_shadowtrispvs = NULL;
611 r_shadow_buffer_numlighttrispvsbytes = 0;
612 r_shadow_buffer_lighttrispvs = NULL;
614 r_shadow_usingdeferredprepass = false;
615 r_shadow_prepass_width = r_shadow_prepass_height = 0;
617 // determine renderpath specific capabilities, we don't need to figure
618 // these out per frame...
619 switch(vid.renderpath)
621 case RENDERPATH_GL20:
622 r_shadow_bouncegrid_state.allowdirectionalshading = true;
623 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
625 case RENDERPATH_GLES2:
626 // for performance reasons, do not use directional shading on GLES devices
627 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
629 // these renderpaths do not currently have the code to display the bouncegrid, so disable it on them...
630 case RENDERPATH_GL11:
631 case RENDERPATH_GL13:
632 case RENDERPATH_GLES1:
633 case RENDERPATH_SOFT:
634 case RENDERPATH_D3D9:
635 case RENDERPATH_D3D10:
636 case RENDERPATH_D3D11:
641 static void R_Shadow_FreeDeferred(void);
642 static void r_shadow_shutdown(void)
645 R_Shadow_UncompileWorldLights();
647 R_Shadow_FreeShadowMaps();
649 r_shadow_usingdeferredprepass = false;
650 if (r_shadow_prepass_width)
651 R_Shadow_FreeDeferred();
652 r_shadow_prepass_width = r_shadow_prepass_height = 0;
655 r_shadow_scenemaxlights = 0;
656 r_shadow_scenenumlights = 0;
657 if (r_shadow_scenelightlist)
658 Mem_Free(r_shadow_scenelightlist);
659 r_shadow_scenelightlist = NULL;
660 r_shadow_bouncegrid_state.highpixels = NULL;
661 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
662 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
663 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
664 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
665 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
666 r_shadow_bouncegrid_state.maxsplatpaths = 0;
667 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
668 r_shadow_attenuationgradienttexture = NULL;
669 r_shadow_attenuation2dtexture = NULL;
670 r_shadow_attenuation3dtexture = NULL;
671 R_FreeTexturePool(&r_shadow_texturepool);
672 R_FreeTexturePool(&r_shadow_filters_texturepool);
673 maxshadowtriangles = 0;
675 Mem_Free(shadowelements);
676 shadowelements = NULL;
678 Mem_Free(shadowvertex3f);
679 shadowvertex3f = NULL;
682 Mem_Free(vertexupdate);
685 Mem_Free(vertexremap);
691 Mem_Free(shadowmark);
694 Mem_Free(shadowmarklist);
695 shadowmarklist = NULL;
700 Mem_Free(shadowsides);
703 Mem_Free(shadowsideslist);
704 shadowsideslist = NULL;
705 r_shadow_buffer_numleafpvsbytes = 0;
706 if (r_shadow_buffer_visitingleafpvs)
707 Mem_Free(r_shadow_buffer_visitingleafpvs);
708 r_shadow_buffer_visitingleafpvs = NULL;
709 if (r_shadow_buffer_leafpvs)
710 Mem_Free(r_shadow_buffer_leafpvs);
711 r_shadow_buffer_leafpvs = NULL;
712 if (r_shadow_buffer_leaflist)
713 Mem_Free(r_shadow_buffer_leaflist);
714 r_shadow_buffer_leaflist = NULL;
715 r_shadow_buffer_numsurfacepvsbytes = 0;
716 if (r_shadow_buffer_surfacepvs)
717 Mem_Free(r_shadow_buffer_surfacepvs);
718 r_shadow_buffer_surfacepvs = NULL;
719 if (r_shadow_buffer_surfacelist)
720 Mem_Free(r_shadow_buffer_surfacelist);
721 r_shadow_buffer_surfacelist = NULL;
722 if (r_shadow_buffer_surfacesides)
723 Mem_Free(r_shadow_buffer_surfacesides);
724 r_shadow_buffer_surfacesides = NULL;
725 r_shadow_buffer_numshadowtrispvsbytes = 0;
726 if (r_shadow_buffer_shadowtrispvs)
727 Mem_Free(r_shadow_buffer_shadowtrispvs);
728 r_shadow_buffer_numlighttrispvsbytes = 0;
729 if (r_shadow_buffer_lighttrispvs)
730 Mem_Free(r_shadow_buffer_lighttrispvs);
733 static void r_shadow_newmap(void)
735 r_shadow_bouncegrid_state.highpixels = NULL;
736 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
737 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
738 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
739 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
740 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
741 r_shadow_bouncegrid_state.maxsplatpaths = 0;
742 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
743 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
744 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
745 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
746 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
747 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
748 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
749 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
750 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
751 R_Shadow_EditLights_Reload_f();
754 void R_Shadow_Init(void)
756 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
757 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
758 Cvar_RegisterVariable(&r_shadow_usebihculling);
759 Cvar_RegisterVariable(&r_shadow_usenormalmap);
760 Cvar_RegisterVariable(&r_shadow_debuglight);
761 Cvar_RegisterVariable(&r_shadow_deferred);
762 Cvar_RegisterVariable(&r_shadow_gloss);
763 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
764 Cvar_RegisterVariable(&r_shadow_glossintensity);
765 Cvar_RegisterVariable(&r_shadow_glossexponent);
766 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
767 Cvar_RegisterVariable(&r_shadow_glossexact);
768 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
769 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
770 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
771 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
772 Cvar_RegisterVariable(&r_shadow_projectdistance);
773 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
774 Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
775 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
776 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
777 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
778 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
779 Cvar_RegisterVariable(&r_shadow_realtime_world);
780 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
781 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
782 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
783 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
784 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
785 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
786 Cvar_RegisterVariable(&r_shadow_scissor);
787 Cvar_RegisterVariable(&r_shadow_shadowmapping);
788 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
789 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
790 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
791 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
792 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
793 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
794 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
795 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturesize);
796 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
797 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
798 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
799 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
800 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
801 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
802 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
803 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
804 Cvar_RegisterVariable(&r_shadow_polygonfactor);
805 Cvar_RegisterVariable(&r_shadow_polygonoffset);
806 Cvar_RegisterVariable(&r_shadow_texture3d);
807 Cvar_RegisterVariable(&r_shadow_bouncegrid);
808 Cvar_RegisterVariable(&r_shadow_bouncegrid_blur);
809 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
810 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_bounceminimumintensity);
811 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_culllightpaths);
812 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_directionalshading);
813 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_dlightparticlemultiplier);
814 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_hitmodels);
815 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_lightradiusscale);
816 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxbounce);
817 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxphotons);
818 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_quality);
819 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_spacing);
820 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_updateinterval);
821 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_x);
822 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_y);
823 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_z);
824 Cvar_RegisterVariable(&r_shadow_bouncegrid_floatcolors);
825 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
826 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
827 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize_conespread);
828 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize_initial);
829 Cvar_RegisterVariable(&r_shadow_bouncegrid_normalizevectors);
830 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
831 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
832 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_seed);
833 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_type);
834 Cvar_RegisterVariable(&r_shadow_bouncegrid_sortlightpaths);
835 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
836 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_bounceminimumintensity);
837 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
838 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
839 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
840 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxphotons);
841 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_quality);
842 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_spacing);
843 Cvar_RegisterVariable(&r_coronas);
844 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
845 Cvar_RegisterVariable(&r_coronas_occlusionquery);
846 Cvar_RegisterVariable(&gl_flashblend);
847 Cvar_RegisterVariable(&gl_ext_separatestencil);
848 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
849 R_Shadow_EditLights_Init();
850 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
851 r_shadow_scenemaxlights = 0;
852 r_shadow_scenenumlights = 0;
853 r_shadow_scenelightlist = NULL;
854 maxshadowtriangles = 0;
855 shadowelements = NULL;
856 maxshadowvertices = 0;
857 shadowvertex3f = NULL;
865 shadowmarklist = NULL;
870 shadowsideslist = NULL;
871 r_shadow_buffer_numleafpvsbytes = 0;
872 r_shadow_buffer_visitingleafpvs = NULL;
873 r_shadow_buffer_leafpvs = NULL;
874 r_shadow_buffer_leaflist = NULL;
875 r_shadow_buffer_numsurfacepvsbytes = 0;
876 r_shadow_buffer_surfacepvs = NULL;
877 r_shadow_buffer_surfacelist = NULL;
878 r_shadow_buffer_surfacesides = NULL;
879 r_shadow_buffer_shadowtrispvs = NULL;
880 r_shadow_buffer_lighttrispvs = NULL;
881 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
884 matrix4x4_t matrix_attenuationxyz =
887 {0.5, 0.0, 0.0, 0.5},
888 {0.0, 0.5, 0.0, 0.5},
889 {0.0, 0.0, 0.5, 0.5},
894 matrix4x4_t matrix_attenuationz =
897 {0.0, 0.0, 0.5, 0.5},
898 {0.0, 0.0, 0.0, 0.5},
899 {0.0, 0.0, 0.0, 0.5},
904 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
906 numvertices = ((numvertices + 255) & ~255) * vertscale;
907 numtriangles = ((numtriangles + 255) & ~255) * triscale;
908 // make sure shadowelements is big enough for this volume
909 if (maxshadowtriangles < numtriangles)
911 maxshadowtriangles = numtriangles;
913 Mem_Free(shadowelements);
914 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
916 // make sure shadowvertex3f is big enough for this volume
917 if (maxshadowvertices < numvertices)
919 maxshadowvertices = numvertices;
921 Mem_Free(shadowvertex3f);
922 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
926 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
928 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
929 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
930 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
931 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
932 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
934 if (r_shadow_buffer_visitingleafpvs)
935 Mem_Free(r_shadow_buffer_visitingleafpvs);
936 if (r_shadow_buffer_leafpvs)
937 Mem_Free(r_shadow_buffer_leafpvs);
938 if (r_shadow_buffer_leaflist)
939 Mem_Free(r_shadow_buffer_leaflist);
940 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
941 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
942 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
943 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
945 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
947 if (r_shadow_buffer_surfacepvs)
948 Mem_Free(r_shadow_buffer_surfacepvs);
949 if (r_shadow_buffer_surfacelist)
950 Mem_Free(r_shadow_buffer_surfacelist);
951 if (r_shadow_buffer_surfacesides)
952 Mem_Free(r_shadow_buffer_surfacesides);
953 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
954 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
955 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
956 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
958 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
960 if (r_shadow_buffer_shadowtrispvs)
961 Mem_Free(r_shadow_buffer_shadowtrispvs);
962 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
963 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
965 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
967 if (r_shadow_buffer_lighttrispvs)
968 Mem_Free(r_shadow_buffer_lighttrispvs);
969 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
970 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
974 void R_Shadow_PrepareShadowMark(int numtris)
976 // make sure shadowmark is big enough for this volume
977 if (maxshadowmark < numtris)
979 maxshadowmark = numtris;
981 Mem_Free(shadowmark);
983 Mem_Free(shadowmarklist);
984 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
985 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
989 // if shadowmarkcount wrapped we clear the array and adjust accordingly
990 if (shadowmarkcount == 0)
993 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
998 void R_Shadow_PrepareShadowSides(int numtris)
1000 if (maxshadowsides < numtris)
1002 maxshadowsides = numtris;
1004 Mem_Free(shadowsides);
1005 if (shadowsideslist)
1006 Mem_Free(shadowsideslist);
1007 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
1008 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
1013 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)
1016 int outtriangles = 0, outvertices = 0;
1018 const float *vertex;
1019 float ratio, direction[3], projectvector[3];
1021 if (projectdirection)
1022 VectorScale(projectdirection, projectdistance, projectvector);
1024 VectorClear(projectvector);
1026 // create the vertices
1027 if (projectdirection)
1029 for (i = 0;i < numshadowmarktris;i++)
1031 element = inelement3i + shadowmarktris[i] * 3;
1032 for (j = 0;j < 3;j++)
1034 if (vertexupdate[element[j]] != vertexupdatenum)
1036 vertexupdate[element[j]] = vertexupdatenum;
1037 vertexremap[element[j]] = outvertices;
1038 vertex = invertex3f + element[j] * 3;
1039 // project one copy of the vertex according to projectvector
1040 VectorCopy(vertex, outvertex3f);
1041 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1050 for (i = 0;i < numshadowmarktris;i++)
1052 element = inelement3i + shadowmarktris[i] * 3;
1053 for (j = 0;j < 3;j++)
1055 if (vertexupdate[element[j]] != vertexupdatenum)
1057 vertexupdate[element[j]] = vertexupdatenum;
1058 vertexremap[element[j]] = outvertices;
1059 vertex = invertex3f + element[j] * 3;
1060 // project one copy of the vertex to the sphere radius of the light
1061 // (FIXME: would projecting it to the light box be better?)
1062 VectorSubtract(vertex, projectorigin, direction);
1063 ratio = projectdistance / VectorLength(direction);
1064 VectorCopy(vertex, outvertex3f);
1065 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1073 if (r_shadow_frontsidecasting.integer)
1075 for (i = 0;i < numshadowmarktris;i++)
1077 int remappedelement[3];
1079 const int *neighbortriangle;
1081 markindex = shadowmarktris[i] * 3;
1082 element = inelement3i + markindex;
1083 neighbortriangle = inneighbor3i + markindex;
1084 // output the front and back triangles
1085 outelement3i[0] = vertexremap[element[0]];
1086 outelement3i[1] = vertexremap[element[1]];
1087 outelement3i[2] = vertexremap[element[2]];
1088 outelement3i[3] = vertexremap[element[2]] + 1;
1089 outelement3i[4] = vertexremap[element[1]] + 1;
1090 outelement3i[5] = vertexremap[element[0]] + 1;
1094 // output the sides (facing outward from this triangle)
1095 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1097 remappedelement[0] = vertexremap[element[0]];
1098 remappedelement[1] = vertexremap[element[1]];
1099 outelement3i[0] = remappedelement[1];
1100 outelement3i[1] = remappedelement[0];
1101 outelement3i[2] = remappedelement[0] + 1;
1102 outelement3i[3] = remappedelement[1];
1103 outelement3i[4] = remappedelement[0] + 1;
1104 outelement3i[5] = remappedelement[1] + 1;
1109 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1111 remappedelement[1] = vertexremap[element[1]];
1112 remappedelement[2] = vertexremap[element[2]];
1113 outelement3i[0] = remappedelement[2];
1114 outelement3i[1] = remappedelement[1];
1115 outelement3i[2] = remappedelement[1] + 1;
1116 outelement3i[3] = remappedelement[2];
1117 outelement3i[4] = remappedelement[1] + 1;
1118 outelement3i[5] = remappedelement[2] + 1;
1123 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1125 remappedelement[0] = vertexremap[element[0]];
1126 remappedelement[2] = vertexremap[element[2]];
1127 outelement3i[0] = remappedelement[0];
1128 outelement3i[1] = remappedelement[2];
1129 outelement3i[2] = remappedelement[2] + 1;
1130 outelement3i[3] = remappedelement[0];
1131 outelement3i[4] = remappedelement[2] + 1;
1132 outelement3i[5] = remappedelement[0] + 1;
1141 for (i = 0;i < numshadowmarktris;i++)
1143 int remappedelement[3];
1145 const int *neighbortriangle;
1147 markindex = shadowmarktris[i] * 3;
1148 element = inelement3i + markindex;
1149 neighbortriangle = inneighbor3i + markindex;
1150 // output the front and back triangles
1151 outelement3i[0] = vertexremap[element[2]];
1152 outelement3i[1] = vertexremap[element[1]];
1153 outelement3i[2] = vertexremap[element[0]];
1154 outelement3i[3] = vertexremap[element[0]] + 1;
1155 outelement3i[4] = vertexremap[element[1]] + 1;
1156 outelement3i[5] = vertexremap[element[2]] + 1;
1160 // output the sides (facing outward from this triangle)
1161 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1163 remappedelement[0] = vertexremap[element[0]];
1164 remappedelement[1] = vertexremap[element[1]];
1165 outelement3i[0] = remappedelement[0];
1166 outelement3i[1] = remappedelement[1];
1167 outelement3i[2] = remappedelement[1] + 1;
1168 outelement3i[3] = remappedelement[0];
1169 outelement3i[4] = remappedelement[1] + 1;
1170 outelement3i[5] = remappedelement[0] + 1;
1175 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1177 remappedelement[1] = vertexremap[element[1]];
1178 remappedelement[2] = vertexremap[element[2]];
1179 outelement3i[0] = remappedelement[1];
1180 outelement3i[1] = remappedelement[2];
1181 outelement3i[2] = remappedelement[2] + 1;
1182 outelement3i[3] = remappedelement[1];
1183 outelement3i[4] = remappedelement[2] + 1;
1184 outelement3i[5] = remappedelement[1] + 1;
1189 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1191 remappedelement[0] = vertexremap[element[0]];
1192 remappedelement[2] = vertexremap[element[2]];
1193 outelement3i[0] = remappedelement[2];
1194 outelement3i[1] = remappedelement[0];
1195 outelement3i[2] = remappedelement[0] + 1;
1196 outelement3i[3] = remappedelement[2];
1197 outelement3i[4] = remappedelement[0] + 1;
1198 outelement3i[5] = remappedelement[2] + 1;
1206 *outnumvertices = outvertices;
1207 return outtriangles;
1210 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)
1213 int outtriangles = 0, outvertices = 0;
1215 const float *vertex;
1216 float ratio, direction[3], projectvector[3];
1219 if (projectdirection)
1220 VectorScale(projectdirection, projectdistance, projectvector);
1222 VectorClear(projectvector);
1224 for (i = 0;i < numshadowmarktris;i++)
1226 int remappedelement[3];
1228 const int *neighbortriangle;
1230 markindex = shadowmarktris[i] * 3;
1231 neighbortriangle = inneighbor3i + markindex;
1232 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1233 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1234 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1235 if (side[0] + side[1] + side[2] == 0)
1239 element = inelement3i + markindex;
1241 // create the vertices
1242 for (j = 0;j < 3;j++)
1244 if (side[j] + side[j+1] == 0)
1247 if (vertexupdate[k] != vertexupdatenum)
1249 vertexupdate[k] = vertexupdatenum;
1250 vertexremap[k] = outvertices;
1251 vertex = invertex3f + k * 3;
1252 VectorCopy(vertex, outvertex3f);
1253 if (projectdirection)
1255 // project one copy of the vertex according to projectvector
1256 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1260 // project one copy of the vertex to the sphere radius of the light
1261 // (FIXME: would projecting it to the light box be better?)
1262 VectorSubtract(vertex, projectorigin, direction);
1263 ratio = projectdistance / VectorLength(direction);
1264 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1271 // output the sides (facing outward from this triangle)
1274 remappedelement[0] = vertexremap[element[0]];
1275 remappedelement[1] = vertexremap[element[1]];
1276 outelement3i[0] = remappedelement[1];
1277 outelement3i[1] = remappedelement[0];
1278 outelement3i[2] = remappedelement[0] + 1;
1279 outelement3i[3] = remappedelement[1];
1280 outelement3i[4] = remappedelement[0] + 1;
1281 outelement3i[5] = remappedelement[1] + 1;
1288 remappedelement[1] = vertexremap[element[1]];
1289 remappedelement[2] = vertexremap[element[2]];
1290 outelement3i[0] = remappedelement[2];
1291 outelement3i[1] = remappedelement[1];
1292 outelement3i[2] = remappedelement[1] + 1;
1293 outelement3i[3] = remappedelement[2];
1294 outelement3i[4] = remappedelement[1] + 1;
1295 outelement3i[5] = remappedelement[2] + 1;
1302 remappedelement[0] = vertexremap[element[0]];
1303 remappedelement[2] = vertexremap[element[2]];
1304 outelement3i[0] = remappedelement[0];
1305 outelement3i[1] = remappedelement[2];
1306 outelement3i[2] = remappedelement[2] + 1;
1307 outelement3i[3] = remappedelement[0];
1308 outelement3i[4] = remappedelement[2] + 1;
1309 outelement3i[5] = remappedelement[0] + 1;
1316 *outnumvertices = outvertices;
1317 return outtriangles;
1320 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)
1326 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1328 tend = firsttriangle + numtris;
1329 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1331 // surface box entirely inside light box, no box cull
1332 if (projectdirection)
1334 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1336 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1337 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1338 shadowmarklist[numshadowmark++] = t;
1343 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1344 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1345 shadowmarklist[numshadowmark++] = t;
1350 // surface box not entirely inside light box, cull each triangle
1351 if (projectdirection)
1353 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1355 v[0] = invertex3f + e[0] * 3;
1356 v[1] = invertex3f + e[1] * 3;
1357 v[2] = invertex3f + e[2] * 3;
1358 TriangleNormal(v[0], v[1], v[2], normal);
1359 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1360 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1361 shadowmarklist[numshadowmark++] = t;
1366 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1368 v[0] = invertex3f + e[0] * 3;
1369 v[1] = invertex3f + e[1] * 3;
1370 v[2] = invertex3f + e[2] * 3;
1371 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1372 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1373 shadowmarklist[numshadowmark++] = t;
1379 static qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1384 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1386 // check if the shadow volume intersects the near plane
1388 // a ray between the eye and light origin may intersect the caster,
1389 // indicating that the shadow may touch the eye location, however we must
1390 // test the near plane (a polygon), not merely the eye location, so it is
1391 // easiest to enlarge the caster bounding shape slightly for this.
1397 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)
1399 int i, tris, outverts;
1400 if (projectdistance < 0.1)
1402 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1405 if (!numverts || !nummarktris)
1407 // make sure shadowelements is big enough for this volume
1408 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1409 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1411 if (maxvertexupdate < numverts)
1413 maxvertexupdate = numverts;
1415 Mem_Free(vertexupdate);
1417 Mem_Free(vertexremap);
1418 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1419 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1420 vertexupdatenum = 0;
1423 if (vertexupdatenum == 0)
1425 vertexupdatenum = 1;
1426 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1427 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1430 for (i = 0;i < nummarktris;i++)
1431 shadowmark[marktris[i]] = shadowmarkcount;
1433 if (r_shadow_compilingrtlight)
1435 // if we're compiling an rtlight, capture the mesh
1436 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1437 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1438 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1439 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1441 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1443 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1444 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1445 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1449 // decide which type of shadow to generate and set stencil mode
1450 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1451 // generate the sides or a solid volume, depending on type
1452 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1453 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1455 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1456 r_refdef.stats[r_stat_lights_dynamicshadowtriangles] += tris;
1457 r_refdef.stats[r_stat_lights_shadowtriangles] += tris;
1458 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1460 // increment stencil if frontface is infront of depthbuffer
1461 GL_CullFace(r_refdef.view.cullface_front);
1462 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1463 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1464 // decrement stencil if backface is infront of depthbuffer
1465 GL_CullFace(r_refdef.view.cullface_back);
1466 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1468 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1470 // decrement stencil if backface is behind depthbuffer
1471 GL_CullFace(r_refdef.view.cullface_front);
1472 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1473 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1474 // increment stencil if frontface is behind depthbuffer
1475 GL_CullFace(r_refdef.view.cullface_back);
1476 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1478 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1479 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1483 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1485 // p1, p2, p3 are in the cubemap's local coordinate system
1486 // bias = border/(size - border)
1489 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1490 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1491 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1492 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1494 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1495 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1496 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1497 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1499 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1500 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1501 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1503 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1504 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1505 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1506 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1508 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1509 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1510 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1511 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1513 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1514 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1515 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1517 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1518 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1519 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1520 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1522 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1523 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1524 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1525 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1527 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1528 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1529 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1534 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1536 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1537 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1540 VectorSubtract(maxs, mins, radius);
1541 VectorScale(radius, 0.5f, radius);
1542 VectorAdd(mins, radius, center);
1543 Matrix4x4_Transform(worldtolight, center, lightcenter);
1544 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1545 VectorSubtract(lightcenter, lightradius, pmin);
1546 VectorAdd(lightcenter, lightradius, pmax);
1548 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1549 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1550 if(ap1 > bias*an1 && ap2 > bias*an2)
1552 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1553 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1554 if(an1 > bias*ap1 && an2 > bias*ap2)
1556 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1557 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1559 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1560 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1561 if(ap1 > bias*an1 && ap2 > bias*an2)
1563 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1564 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1565 if(an1 > bias*ap1 && an2 > bias*ap2)
1567 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1568 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1570 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1571 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1572 if(ap1 > bias*an1 && ap2 > bias*an2)
1574 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1575 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1576 if(an1 > bias*ap1 && an2 > bias*ap2)
1578 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1579 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1584 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1586 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1588 // p is in the cubemap's local coordinate system
1589 // bias = border/(size - border)
1590 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1591 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1592 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1594 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1595 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1596 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1597 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1598 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1599 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1603 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1607 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1608 float scale = (size - 2*border)/size, len;
1609 float bias = border / (float)(size - border), dp, dn, ap, an;
1610 // check if cone enclosing side would cross frustum plane
1611 scale = 2 / (scale*scale + 2);
1612 Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
1613 for (i = 0;i < 5;i++)
1615 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
1617 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1618 len = scale*VectorLength2(n);
1619 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1620 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1621 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1623 if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1625 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1626 len = scale*VectorLength2(n);
1627 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1628 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1629 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1631 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1632 // check if frustum corners/origin cross plane sides
1634 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1635 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1636 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1637 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1638 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1639 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1640 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1641 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1642 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1643 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1644 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1645 for (i = 0;i < 4;i++)
1647 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1648 VectorSubtract(n, p, n);
1649 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1650 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1651 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1652 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1653 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1654 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1655 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1656 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1657 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1660 // finite version, assumes corners are a finite distance from origin dependent on far plane
1661 for (i = 0;i < 5;i++)
1663 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1664 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1665 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1666 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1667 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1668 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1669 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1670 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1671 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1672 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1675 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1678 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)
1686 int mask, surfacemask = 0;
1687 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1689 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1690 tend = firsttriangle + numtris;
1691 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1693 // surface box entirely inside light box, no box cull
1694 if (projectdirection)
1696 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1698 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1699 TriangleNormal(v[0], v[1], v[2], normal);
1700 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1702 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1703 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1704 surfacemask |= mask;
1707 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;
1708 shadowsides[numshadowsides] = mask;
1709 shadowsideslist[numshadowsides++] = t;
1716 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1718 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1719 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1721 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1722 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1723 surfacemask |= mask;
1726 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;
1727 shadowsides[numshadowsides] = mask;
1728 shadowsideslist[numshadowsides++] = t;
1736 // surface box not entirely inside light box, cull each triangle
1737 if (projectdirection)
1739 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1741 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1742 TriangleNormal(v[0], v[1], v[2], normal);
1743 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1744 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1746 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1747 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1748 surfacemask |= mask;
1751 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;
1752 shadowsides[numshadowsides] = mask;
1753 shadowsideslist[numshadowsides++] = t;
1760 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1762 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1763 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1764 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1766 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1767 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1768 surfacemask |= mask;
1771 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;
1772 shadowsides[numshadowsides] = mask;
1773 shadowsideslist[numshadowsides++] = t;
1782 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)
1784 int i, j, outtriangles = 0;
1785 int *outelement3i[6];
1786 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1788 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1789 // make sure shadowelements is big enough for this mesh
1790 if (maxshadowtriangles < outtriangles)
1791 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1793 // compute the offset and size of the separate index lists for each cubemap side
1795 for (i = 0;i < 6;i++)
1797 outelement3i[i] = shadowelements + outtriangles * 3;
1798 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1799 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1800 outtriangles += sidetotals[i];
1803 // gather up the (sparse) triangles into separate index lists for each cubemap side
1804 for (i = 0;i < numsidetris;i++)
1806 const int *element = elements + sidetris[i] * 3;
1807 for (j = 0;j < 6;j++)
1809 if (sides[i] & (1 << j))
1811 outelement3i[j][0] = element[0];
1812 outelement3i[j][1] = element[1];
1813 outelement3i[j][2] = element[2];
1814 outelement3i[j] += 3;
1819 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1822 static void R_Shadow_MakeTextures_MakeCorona(void)
1826 unsigned char pixels[32][32][4];
1827 for (y = 0;y < 32;y++)
1829 dy = (y - 15.5f) * (1.0f / 16.0f);
1830 for (x = 0;x < 32;x++)
1832 dx = (x - 15.5f) * (1.0f / 16.0f);
1833 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1834 a = bound(0, a, 255);
1835 pixels[y][x][0] = a;
1836 pixels[y][x][1] = a;
1837 pixels[y][x][2] = a;
1838 pixels[y][x][3] = 255;
1841 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, false);
1844 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1846 float dist = sqrt(x*x+y*y+z*z);
1847 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1848 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1849 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1852 static void R_Shadow_MakeTextures(void)
1855 float intensity, dist;
1857 R_Shadow_FreeShadowMaps();
1858 R_FreeTexturePool(&r_shadow_texturepool);
1859 r_shadow_texturepool = R_AllocTexturePool();
1860 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1861 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1862 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1863 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1864 for (x = 0;x <= ATTENTABLESIZE;x++)
1866 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1867 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1868 r_shadow_attentable[x] = bound(0, intensity, 1);
1870 // 1D gradient texture
1871 for (x = 0;x < ATTEN1DSIZE;x++)
1872 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1873 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1874 // 2D circle texture
1875 for (y = 0;y < ATTEN2DSIZE;y++)
1876 for (x = 0;x < ATTEN2DSIZE;x++)
1877 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);
1878 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1879 // 3D sphere texture
1880 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1882 for (z = 0;z < ATTEN3DSIZE;z++)
1883 for (y = 0;y < ATTEN3DSIZE;y++)
1884 for (x = 0;x < ATTEN3DSIZE;x++)
1885 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));
1886 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);
1889 r_shadow_attenuation3dtexture = NULL;
1892 R_Shadow_MakeTextures_MakeCorona();
1894 // Editor light sprites
1895 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1912 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1913 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1930 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1931 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1948 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1949 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1966 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1967 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1984 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1985 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
2002 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
2005 void R_Shadow_ValidateCvars(void)
2007 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
2008 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
2009 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
2010 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
2011 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
2012 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
2015 void R_Shadow_RenderMode_Begin(void)
2021 R_Shadow_ValidateCvars();
2023 if (!r_shadow_attenuation2dtexture
2024 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
2025 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
2026 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
2027 R_Shadow_MakeTextures();
2030 R_Mesh_ResetTextureState();
2031 GL_BlendFunc(GL_ONE, GL_ZERO);
2032 GL_DepthRange(0, 1);
2033 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
2035 GL_DepthMask(false);
2036 GL_Color(0, 0, 0, 1);
2037 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2039 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2041 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
2043 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
2044 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
2046 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
2048 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
2049 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
2053 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
2054 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
2057 switch(vid.renderpath)
2059 case RENDERPATH_GL20:
2060 case RENDERPATH_D3D9:
2061 case RENDERPATH_D3D10:
2062 case RENDERPATH_D3D11:
2063 case RENDERPATH_SOFT:
2064 case RENDERPATH_GLES2:
2065 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
2067 case RENDERPATH_GL11:
2068 case RENDERPATH_GL13:
2069 case RENDERPATH_GLES1:
2070 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
2071 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
2072 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
2073 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
2074 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
2075 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
2077 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
2083 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
2084 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
2085 r_shadow_drawbuffer = drawbuffer;
2086 r_shadow_readbuffer = readbuffer;
2088 r_shadow_cullface_front = r_refdef.view.cullface_front;
2089 r_shadow_cullface_back = r_refdef.view.cullface_back;
2092 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
2094 rsurface.rtlight = rtlight;
2097 void R_Shadow_RenderMode_Reset(void)
2099 R_Mesh_ResetTextureState();
2100 R_Mesh_SetRenderTargets(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture, NULL, NULL, NULL);
2101 R_SetViewport(&r_refdef.view.viewport);
2102 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
2103 GL_DepthRange(0, 1);
2105 GL_DepthMask(false);
2106 GL_DepthFunc(GL_LEQUAL);
2107 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2108 r_refdef.view.cullface_front = r_shadow_cullface_front;
2109 r_refdef.view.cullface_back = r_shadow_cullface_back;
2110 GL_CullFace(r_refdef.view.cullface_back);
2111 GL_Color(1, 1, 1, 1);
2112 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2113 GL_BlendFunc(GL_ONE, GL_ZERO);
2114 R_SetupShader_Generic_NoTexture(false, false);
2115 r_shadow_usingshadowmap2d = false;
2116 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2119 void R_Shadow_ClearStencil(void)
2121 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2122 r_refdef.stats[r_stat_lights_clears]++;
2125 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2127 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2128 if (r_shadow_rendermode == mode)
2130 R_Shadow_RenderMode_Reset();
2131 GL_DepthFunc(GL_LESS);
2132 GL_ColorMask(0, 0, 0, 0);
2133 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2134 GL_CullFace(GL_NONE);
2135 R_SetupShader_DepthOrShadow(false, false, false); // FIXME test if we have a skeletal model?
2136 r_shadow_rendermode = mode;
2141 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2142 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2143 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2145 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2146 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2147 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2152 static void R_Shadow_MakeVSDCT(void)
2154 // maps to a 2x3 texture rectangle with normalized coordinates
2159 // stores abs(dir.xy), offset.xy/2.5
2160 unsigned char data[4*6] =
2162 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2163 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2164 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2165 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2166 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2167 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2169 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2172 static void R_Shadow_MakeShadowMap(int texturesize)
2174 switch (r_shadow_shadowmode)
2176 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2177 if (r_shadow_shadowmap2ddepthtexture) return;
2178 if (r_fb.usedepthtextures)
2180 r_shadow_shadowmap2ddepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? (r_shadow_shadowmapsampler ? TEXTYPE_SHADOWMAP24_COMP : TEXTYPE_SHADOWMAP24_RAW) : (r_shadow_shadowmapsampler ? TEXTYPE_SHADOWMAP16_COMP : TEXTYPE_SHADOWMAP16_RAW), r_shadow_shadowmapsampler);
2181 r_shadow_shadowmap2ddepthbuffer = NULL;
2182 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2186 r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", texturesize, texturesize, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2187 r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
2188 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2196 void R_Shadow_ClearShadowMapTexture(void)
2198 r_viewport_t viewport;
2199 float clearcolor[4];
2201 // if they don't exist, create our textures now
2202 if (!r_shadow_shadowmap2ddepthtexture)
2203 R_Shadow_MakeShadowMap(r_shadow_shadowmaptexturesize);
2204 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2205 R_Shadow_MakeVSDCT();
2207 // we're setting up to render shadowmaps, so change rendermode
2208 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2210 R_Mesh_ResetTextureState();
2211 R_Shadow_RenderMode_Reset();
2212 if (r_shadow_shadowmap2ddepthbuffer)
2213 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2215 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2216 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2217 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2221 // we have to set a viewport to clear anything in some renderpaths (D3D)
2222 R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize, 0, 0, 1.0, 1.0, 0.001f, 1.0f, NULL);
2223 R_SetViewport(&viewport);
2224 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2225 if (r_shadow_shadowmap2ddepthbuffer)
2226 GL_ColorMask(1, 1, 1, 1);
2228 GL_ColorMask(0, 0, 0, 0);
2229 switch (vid.renderpath)
2231 case RENDERPATH_GL11:
2232 case RENDERPATH_GL13:
2233 case RENDERPATH_GL20:
2234 case RENDERPATH_SOFT:
2235 case RENDERPATH_GLES1:
2236 case RENDERPATH_GLES2:
2237 GL_CullFace(r_refdef.view.cullface_back);
2239 case RENDERPATH_D3D9:
2240 case RENDERPATH_D3D10:
2241 case RENDERPATH_D3D11:
2242 // we invert the cull mode because we flip the projection matrix
2243 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2244 GL_CullFace(r_refdef.view.cullface_front);
2247 Vector4Set(clearcolor, 1, 1, 1, 1);
2248 if (r_shadow_shadowmap2ddepthbuffer)
2249 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2251 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2254 static void R_Shadow_SetShadowmapParametersForLight(qboolean noselfshadowpass)
2256 int size = rsurface.rtlight->shadowmapatlassidesize;
2257 float nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2258 float farclip = 1.0f;
2259 float bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2260 r_shadow_lightshadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
2261 r_shadow_lightshadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
2262 r_shadow_lightshadowmap_texturescale[2] = rsurface.rtlight->shadowmapatlasposition[0] + (noselfshadowpass ? size * 2 : 0);
2263 r_shadow_lightshadowmap_texturescale[3] = rsurface.rtlight->shadowmapatlasposition[1];
2264 r_shadow_lightshadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2265 r_shadow_lightshadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2266 r_shadow_lightshadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2267 r_shadow_lightshadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2268 if (r_shadow_shadowmap2ddepthbuffer)
2270 // completely different meaning than in depthtexture approach
2271 r_shadow_lightshadowmap_parameters[1] = 0;
2272 r_shadow_lightshadowmap_parameters[3] = -bias;
2276 static void R_Shadow_RenderMode_ShadowMap(int side, int size, int x, int y)
2278 float nearclip, farclip, bias;
2279 r_viewport_t viewport;
2281 float clearcolor[4];
2283 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_SHADOWMAP2D)
2285 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2287 R_Mesh_ResetTextureState();
2288 R_Shadow_RenderMode_Reset();
2289 if (r_shadow_shadowmap2ddepthbuffer)
2290 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2292 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2293 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2294 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2299 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2301 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2303 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
2304 R_SetViewport(&viewport);
2305 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2306 flipped = (side & 1) ^ (side >> 2);
2307 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2308 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2310 Vector4Set(clearcolor, 1,1,1,1);
2311 if (r_shadow_shadowmap2ddepthbuffer)
2312 GL_ColorMask(1,1,1,1);
2314 GL_ColorMask(0,0,0,0);
2315 switch(vid.renderpath)
2317 case RENDERPATH_GL11:
2318 case RENDERPATH_GL13:
2319 case RENDERPATH_GL20:
2320 case RENDERPATH_SOFT:
2321 case RENDERPATH_GLES1:
2322 case RENDERPATH_GLES2:
2323 GL_CullFace(r_refdef.view.cullface_back);
2325 case RENDERPATH_D3D9:
2326 case RENDERPATH_D3D10:
2327 case RENDERPATH_D3D11:
2328 // we invert the cull mode because we flip the projection matrix
2329 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2330 GL_CullFace(r_refdef.view.cullface_front);
2334 // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
2335 r_shadow_shadowmapside = side;
2338 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass)
2340 R_Mesh_ResetTextureState();
2343 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2344 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2345 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2346 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2349 R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
2350 R_Shadow_RenderMode_Reset();
2351 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2353 GL_DepthFunc(GL_EQUAL);
2354 // do global setup needed for the chosen lighting mode
2355 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2356 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2357 r_shadow_usingshadowmap2d = shadowmapping;
2358 r_shadow_rendermode = r_shadow_lightingrendermode;
2359 // only draw light where this geometry was already rendered AND the
2360 // stencil is 128 (values other than this mean shadow)
2362 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2364 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2367 static const unsigned short bboxelements[36] =
2377 static const float bboxpoints[8][3] =
2389 void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping)
2392 float vertex3f[8*3];
2393 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2394 // do global setup needed for the chosen lighting mode
2395 R_Shadow_RenderMode_Reset();
2396 r_shadow_rendermode = r_shadow_lightingrendermode;
2397 R_EntityMatrix(&identitymatrix);
2398 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2399 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2400 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
2401 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2403 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
2405 r_shadow_usingshadowmap2d = shadowmapping;
2407 // render the lighting
2408 R_SetupShader_DeferredLight(rsurface.rtlight);
2409 for (i = 0;i < 8;i++)
2410 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2411 GL_ColorMask(1,1,1,1);
2412 GL_DepthMask(false);
2413 GL_DepthRange(0, 1);
2414 GL_PolygonOffset(0, 0);
2416 GL_DepthFunc(GL_GREATER);
2417 GL_CullFace(r_refdef.view.cullface_back);
2418 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
2419 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2422 #define MAXBOUNCEGRIDSPLATSIZE 7
2423 #define MAXBOUNCEGRIDSPLATSIZE1 (MAXBOUNCEGRIDSPLATSIZE+1)
2425 // these are temporary data per-frame, sorted and performed in a more
2426 // cache-friendly order than the original photons
2427 typedef struct r_shadow_bouncegrid_splatpath_s
2433 vec_t splatintensity;
2434 vec_t splatsize_current;
2435 vec_t splatsize_perstep;
2436 int remainingsplats;
2438 r_shadow_bouncegrid_splatpath_t;
2440 static void R_Shadow_BounceGrid_AddSplatPath(vec3_t originalstart, vec3_t originalend, vec3_t color, vec_t distancetraveled)
2450 r_shadow_bouncegrid_splatpath_t *path;
2452 // cull paths that fail R_CullBox in dynamic mode
2453 if (!r_shadow_bouncegrid_state.settings.staticmode
2454 && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
2456 vec3_t cullmins, cullmaxs;
2457 cullmins[0] = min(originalstart[0], originalend[0]) - r_shadow_bouncegrid_state.settings.spacing[0];
2458 cullmins[1] = min(originalstart[1], originalend[1]) - r_shadow_bouncegrid_state.settings.spacing[1];
2459 cullmins[2] = min(originalstart[2], originalend[2]) - r_shadow_bouncegrid_state.settings.spacing[2];
2460 cullmaxs[0] = max(originalstart[0], originalend[0]) + r_shadow_bouncegrid_state.settings.spacing[0];
2461 cullmaxs[1] = max(originalstart[1], originalend[1]) + r_shadow_bouncegrid_state.settings.spacing[1];
2462 cullmaxs[2] = max(originalstart[2], originalend[2]) + r_shadow_bouncegrid_state.settings.spacing[2];
2463 if (R_CullBox(cullmins, cullmaxs))
2467 // if the light path is going upward, reverse it - we always draw down.
2468 if (originalend[2] < originalstart[2])
2470 VectorCopy(originalend, start);
2471 VectorCopy(originalstart, end);
2475 VectorCopy(originalstart, start);
2476 VectorCopy(originalend, end);
2479 // transform to texture pixels
2480 start[0] = (start[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2481 start[1] = (start[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2482 start[2] = (start[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2483 end[0] = (end[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2484 end[1] = (end[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2485 end[2] = (end[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2487 // check if we need to grow the splatpaths array
2488 if (r_shadow_bouncegrid_state.maxsplatpaths <= r_shadow_bouncegrid_state.numsplatpaths)
2490 // double the limit, this will persist from frame to frame so we don't
2491 // make the same mistake each time
2492 r_shadow_bouncegrid_state.maxsplatpaths *= 2;
2493 if (r_shadow_bouncegrid_state.maxsplatpaths < 16384)
2494 r_shadow_bouncegrid_state.maxsplatpaths = 16384;
2495 r_shadow_bouncegrid_state.splatpaths = (r_shadow_bouncegrid_splatpath_t *)Mem_Realloc(r_main_mempool, r_shadow_bouncegrid_state.splatpaths, sizeof(r_shadow_bouncegrid_splatpath_t) * r_shadow_bouncegrid_state.maxsplatpaths);
2498 // divide a series of splats along the length using the maximum axis
2499 VectorSubtract(end, start, diff);
2500 // pick the best axis to trace along
2502 if (diff[1]*diff[1] > diff[bestaxis]*diff[bestaxis])
2504 if (diff[2]*diff[2] > diff[bestaxis]*diff[bestaxis])
2506 len = fabs(diff[bestaxis]);
2508 numsplats = (int)(floor(len + 0.5f));
2510 numsplats = bound(0, numsplats, 1024);
2512 VectorSubtract(originalstart, originalend, originaldir);
2513 VectorNormalize(originaldir);
2515 path = r_shadow_bouncegrid_state.splatpaths + r_shadow_bouncegrid_state.numsplatpaths++;
2516 VectorCopy(start, path->point);
2517 VectorScale(diff, ilen, path->step);
2518 VectorCopy(color, path->splatcolor);
2519 VectorCopy(originaldir, path->splatdir);
2520 path->splatsize_current = r_shadow_bouncegrid_state.settings.lightpathsize_initial + r_shadow_bouncegrid_state.settings.lightpathsize_conespread * distancetraveled * r_shadow_bouncegrid_state.ispacing[0];
2521 path->splatsize_perstep = r_shadow_bouncegrid_state.settings.lightpathsize_conespread;
2522 path->splatintensity = VectorLength(color);
2523 path->remainingsplats = numsplats;
2526 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
2528 qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
2535 // see if there are really any lights to render...
2536 if (enable && r_shadow_bouncegrid_static.integer)
2539 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2540 for (lightindex = 0;lightindex < range;lightindex++)
2542 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2543 if (!light || !(light->flags & flag))
2545 rtlight = &light->rtlight;
2546 // when static, we skip styled lights because they tend to change...
2547 if (rtlight->style > 0)
2549 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
2550 if (!VectorLength2(lightcolor))
2560 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
2562 qboolean s = r_shadow_bouncegrid_static.integer != 0;
2563 float spacing = bound(1.0f, s ? r_shadow_bouncegrid_static_spacing.value : r_shadow_bouncegrid_dynamic_spacing.value, 1024.0f);
2564 float quality = bound(0.0001f, (s ? r_shadow_bouncegrid_static_quality.value : r_shadow_bouncegrid_dynamic_quality.value), 1024.0f);
2565 float bounceminimumintensity = s ? r_shadow_bouncegrid_static_bounceminimumintensity.value : r_shadow_bouncegrid_dynamic_bounceminimumintensity.value;
2567 // prevent any garbage in alignment padded areas as we'll be using memcmp
2568 memset(settings, 0, sizeof(*settings));
2570 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
2571 settings->staticmode = s;
2572 settings->blur = r_shadow_bouncegrid_blur.integer != 0;
2573 settings->floatcolors = bound(0, r_shadow_bouncegrid_floatcolors.integer, 2);
2574 settings->lightpathsize_initial = bound(0.0f, r_shadow_bouncegrid_lightpathsize_initial.value, 1024.0f);
2575 settings->lightpathsize_conespread = bound(0.0f, r_shadow_bouncegrid_lightpathsize_conespread.value, 1024.0f);
2576 settings->bounceanglediffuse = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
2577 settings->directionalshading = (s ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_dynamic_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
2578 settings->dlightparticlemultiplier = s ? 0 : r_shadow_bouncegrid_dynamic_dlightparticlemultiplier.value;
2579 settings->hitmodels = s ? false : r_shadow_bouncegrid_dynamic_hitmodels.integer != 0;
2580 settings->includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
2581 settings->lightradiusscale = (s ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_dynamic_lightradiusscale.value);
2582 settings->maxbounce = (s ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_dynamic_maxbounce.integer);
2583 settings->particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
2584 settings->particleintensity = r_shadow_bouncegrid_particleintensity.value * (settings->directionalshading ? 4.0f : 1.0f) * 16384 / (spacing * spacing) / 262144.0f;
2585 settings->maxphotons = s ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_dynamic_maxphotons.integer;
2586 settings->energyperphoton = spacing * spacing / quality;
2587 settings->spacing[0] = spacing;
2588 settings->spacing[1] = spacing;
2589 settings->spacing[2] = spacing;
2590 settings->rng_type = r_shadow_bouncegrid_rng_type.integer;
2591 settings->rng_seed = r_shadow_bouncegrid_rng_seed.integer;
2592 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
2593 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
2594 settings->normalizevectors = r_shadow_bouncegrid_normalizevectors.integer != 0;
2596 // bound the values for sanity
2597 settings->maxphotons = bound(1, settings->maxphotons, 25000000);
2598 settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
2599 settings->maxbounce = bound(0, settings->maxbounce, 16);
2600 settings->spacing[0] = bound(1, settings->spacing[0], 512);
2601 settings->spacing[1] = bound(1, settings->spacing[1], 512);
2602 settings->spacing[2] = bound(1, settings->spacing[2], 512);
2605 static void R_Shadow_BounceGrid_UpdateSpacing(void)
2616 r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
2618 // get the spacing values
2619 spacing[0] = settings->spacing[0];
2620 spacing[1] = settings->spacing[1];
2621 spacing[2] = settings->spacing[2];
2622 ispacing[0] = 1.0f / spacing[0];
2623 ispacing[1] = 1.0f / spacing[1];
2624 ispacing[2] = 1.0f / spacing[2];
2626 // calculate texture size enclosing entire world bounds at the spacing
2627 if (r_refdef.scene.worldmodel)
2631 qboolean bounds_set = false;
2635 // calculate bounds enclosing world lights as they should be noticably tighter
2636 // than the world bounds on maps with unlit monster containers (see e1m7 etc)
2637 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2638 for (lightindex = 0;lightindex < range;lightindex++)
2640 const vec_t *rtlmins, *rtlmaxs;
2642 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2646 rtlight = &light->rtlight;
2647 rtlmins = rtlight->cullmins;
2648 rtlmaxs = rtlight->cullmaxs;
2652 VectorCopy(rtlmins, mins);
2653 VectorCopy(rtlmaxs, maxs);
2658 mins[0] = min(mins[0], rtlmins[0]);
2659 mins[1] = min(mins[1], rtlmins[1]);
2660 mins[2] = min(mins[2], rtlmins[2]);
2661 maxs[0] = max(maxs[0], rtlmaxs[0]);
2662 maxs[1] = max(maxs[1], rtlmaxs[1]);
2663 maxs[2] = max(maxs[2], rtlmaxs[2]);
2667 // limit to no larger than the world bounds
2668 mins[0] = max(mins[0], r_refdef.scene.worldmodel->normalmins[0]);
2669 mins[1] = max(mins[1], r_refdef.scene.worldmodel->normalmins[1]);
2670 mins[2] = max(mins[2], r_refdef.scene.worldmodel->normalmins[2]);
2671 maxs[0] = min(maxs[0], r_refdef.scene.worldmodel->normalmaxs[0]);
2672 maxs[1] = min(maxs[1], r_refdef.scene.worldmodel->normalmaxs[1]);
2673 maxs[2] = min(maxs[2], r_refdef.scene.worldmodel->normalmaxs[2]);
2675 VectorMA(mins, -2.0f, spacing, mins);
2676 VectorMA(maxs, 2.0f, spacing, maxs);
2680 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
2681 VectorSet(maxs, 1048576.0f, 1048576.0f, 1048576.0f);
2683 VectorSubtract(maxs, mins, size);
2684 // now we can calculate the resolution we want
2685 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2686 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2687 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2688 // figure out the exact texture size (honoring power of 2 if required)
2689 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2690 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2691 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2692 if (vid.support.arb_texture_non_power_of_two)
2694 resolution[0] = c[0];
2695 resolution[1] = c[1];
2696 resolution[2] = c[2];
2700 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2701 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2702 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2704 size[0] = spacing[0] * resolution[0];
2705 size[1] = spacing[1] * resolution[1];
2706 size[2] = spacing[2] * resolution[2];
2708 // if dynamic we may or may not want to use the world bounds
2709 // if the dynamic size is smaller than the world bounds, use it instead
2710 if (!settings->staticmode && (r_shadow_bouncegrid_dynamic_x.integer * r_shadow_bouncegrid_dynamic_y.integer * r_shadow_bouncegrid_dynamic_z.integer < resolution[0] * resolution[1] * resolution[2]))
2712 // we know the resolution we want
2713 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
2714 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
2715 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
2716 // now we can calculate the texture size (power of 2 if required)
2717 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2718 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2719 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2720 if (vid.support.arb_texture_non_power_of_two)
2722 resolution[0] = c[0];
2723 resolution[1] = c[1];
2724 resolution[2] = c[2];
2728 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2729 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2730 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2732 size[0] = spacing[0] * resolution[0];
2733 size[1] = spacing[1] * resolution[1];
2734 size[2] = spacing[2] * resolution[2];
2735 // center the rendering on the view
2736 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2737 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2738 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2741 // recalculate the maxs in case the resolution was not satisfactory
2742 VectorAdd(mins, size, maxs);
2744 // check if this changed the texture size
2745 r_shadow_bouncegrid_state.createtexture = !(r_shadow_bouncegrid_state.texture && r_shadow_bouncegrid_state.resolution[0] == resolution[0] && r_shadow_bouncegrid_state.resolution[1] == resolution[1] && r_shadow_bouncegrid_state.resolution[2] == resolution[2] && r_shadow_bouncegrid_state.directional == r_shadow_bouncegrid_state.settings.directionalshading);
2746 r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
2747 VectorCopy(mins, r_shadow_bouncegrid_state.mins);
2748 VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
2749 VectorCopy(size, r_shadow_bouncegrid_state.size);
2750 VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
2751 VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
2752 VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
2754 // reallocate pixels for this update if needed...
2755 r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
2756 r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
2757 r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
2758 numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
2759 if (r_shadow_bouncegrid_state.numpixels != numpixels)
2761 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
2762 r_shadow_bouncegrid_state.highpixels = NULL;
2763 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2764 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2765 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2766 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2767 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2768 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2769 r_shadow_bouncegrid_state.numpixels = numpixels;
2772 // update the bouncegrid matrix to put it in the world properly
2773 memset(m, 0, sizeof(m));
2774 m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
2775 m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
2776 m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
2777 m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
2778 m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
2779 m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
2781 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
2784 // enumerate world rtlights and sum the overall amount of light in the world,
2785 // from that we can calculate a scaling factor to fairly distribute photons
2786 // to all the lights
2788 // this modifies rtlight->photoncolor and rtlight->photons
2789 static void R_Shadow_BounceGrid_AssignPhotons(r_shadow_bouncegrid_settings_t *settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
2791 float normalphotonscaling;
2792 float photonscaling;
2793 float photonintensity;
2794 float photoncount = 0.0f;
2795 float lightintensity;
2801 unsigned int lightindex;
2804 normalphotonscaling = 1.0f / max(0.0001f, settings->energyperphoton);
2805 for (lightindex = 0;lightindex < range2;lightindex++)
2807 if (lightindex < range)
2809 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2812 rtlight = &light->rtlight;
2813 VectorClear(rtlight->bouncegrid_photoncolor);
2814 rtlight->bouncegrid_photons = 0;
2815 rtlight->bouncegrid_hits = 0;
2816 rtlight->bouncegrid_traces = 0;
2817 rtlight->bouncegrid_effectiveradius = 0;
2818 if (!(light->flags & flag))
2820 if (settings->staticmode)
2822 // when static, we skip styled lights because they tend to change...
2823 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2826 else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
2831 rtlight = r_refdef.scene.lights[lightindex - range];
2832 VectorClear(rtlight->bouncegrid_photoncolor);
2833 rtlight->bouncegrid_photons = 0;
2834 rtlight->bouncegrid_hits = 0;
2835 rtlight->bouncegrid_traces = 0;
2836 rtlight->bouncegrid_effectiveradius = 0;
2838 // draw only visible lights (major speedup)
2839 radius = rtlight->radius * settings->lightradiusscale;
2840 cullmins[0] = rtlight->shadoworigin[0] - radius;
2841 cullmins[1] = rtlight->shadoworigin[1] - radius;
2842 cullmins[2] = rtlight->shadoworigin[2] - radius;
2843 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2844 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2845 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2846 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2847 if (!settings->staticmode)
2849 if (R_CullBox(cullmins, cullmaxs))
2851 if (r_refdef.scene.worldmodel
2852 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2853 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2855 if (w * VectorLength2(rtlight->color) == 0.0f)
2858 // a light that does not emit any light before style is applied, can be
2859 // skipped entirely (it may just be a corona)
2860 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2862 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2863 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2864 // skip lights that will emit no photons
2865 if (!VectorLength2(rtlight->bouncegrid_photoncolor))
2867 // shoot particles from this light
2868 // use a calculation for the number of particles that will not
2869 // vary with lightstyle, otherwise we get randomized particle
2870 // distribution, the seeded random is only consistent for a
2871 // consistent number of particles on this light...
2872 s = rtlight->radius;
2873 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2874 if (lightindex >= range)
2875 lightintensity *= settings->dlightparticlemultiplier;
2876 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2877 photoncount += rtlight->bouncegrid_photons;
2878 VectorScale(rtlight->bouncegrid_photoncolor, settings->particleintensity * settings->energyperphoton, rtlight->bouncegrid_photoncolor);
2879 // if the lightstyle happens to be off right now, we can skip actually
2880 // firing the photons, but we did have to count them in the total.
2881 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2882 // rtlight->bouncegrid_photons = 0;
2884 // the user provided an energyperphoton value which we try to use
2885 // if that results in too many photons to shoot this frame, then we cap it
2886 // which causes photons to appear/disappear from frame to frame, so we don't
2887 // like doing that in the typical case
2888 photonscaling = 1.0f;
2889 photonintensity = 1.0f;
2890 if (photoncount > settings->maxphotons)
2892 photonscaling = settings->maxphotons / photoncount;
2893 photonintensity = 1.0f / photonscaling;
2896 // modify the lights to reflect our computed scaling
2897 for (lightindex = 0; lightindex < range2; lightindex++)
2899 if (lightindex < range)
2901 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2904 rtlight = &light->rtlight;
2907 rtlight = r_refdef.scene.lights[lightindex - range];
2908 rtlight->bouncegrid_photons *= photonscaling;
2909 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2913 static int R_Shadow_BounceGrid_SplatPathCompare(const void *pa, const void *pb)
2915 r_shadow_bouncegrid_splatpath_t *a = (r_shadow_bouncegrid_splatpath_t *)pa;
2916 r_shadow_bouncegrid_splatpath_t *b = (r_shadow_bouncegrid_splatpath_t *)pb;
2917 // we only really care about sorting by Z
2918 if (a->point[2] < b->point[2])
2920 if (a->point[2] > b->point[2])
2925 static void R_Shadow_BounceGrid_ClearPixels(void)
2927 // clear the highpixels array we'll be accumulating into
2928 if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2929 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2930 if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2931 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2932 r_shadow_bouncegrid_state.highpixels_index = 0;
2933 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2934 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2937 static void R_Shadow_BounceGrid_PerformSplats(void)
2939 r_shadow_bouncegrid_splatpath_t *splatpaths = r_shadow_bouncegrid_state.splatpaths;
2940 r_shadow_bouncegrid_splatpath_t *splatpath;
2941 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2942 int numsplatpaths = r_shadow_bouncegrid_state.numsplatpaths;
2947 vec_t lightpathsize_current;
2948 vec_t lightpathsize_perstep;
2949 float splatcolor[32];
2951 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2952 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2956 // hush warnings about uninitialized data - pixelbands doesn't change but...
2957 memset(splatcolor, 0, sizeof(splatcolor));
2959 // we use this a lot, so get a local copy
2960 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2962 // sort the splats before we execute them, to reduce cache misses
2963 if (r_shadow_bouncegrid_sortlightpaths.integer)
2964 qsort(splatpaths, numsplatpaths, sizeof(*splatpaths), R_Shadow_BounceGrid_SplatPathCompare);
2966 splatpath = splatpaths;
2967 for (splatindex = 0;splatindex < numsplatpaths;splatindex++, splatpath++)
2969 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2970 // accumulate average shotcolor
2971 VectorCopy(splatpath->splatdir, dir);
2972 splatcolor[ 0] = splatpath->splatcolor[0];
2973 splatcolor[ 1] = splatpath->splatcolor[1];
2974 splatcolor[ 2] = splatpath->splatcolor[2];
2975 splatcolor[ 3] = 0.0f;
2978 // store bentnormal in case the shader has a use for it,
2979 // bentnormal is an intensity-weighted average of the directions,
2980 // and will be normalized on conversion to texture pixels.
2981 splatcolor[ 4] = dir[0] * splatpath->splatintensity;
2982 splatcolor[ 5] = dir[1] * splatpath->splatintensity;
2983 splatcolor[ 6] = dir[2] * splatpath->splatintensity;
2984 splatcolor[ 7] = splatpath->splatintensity;
2985 // for each color component (R, G, B) calculate the amount that a
2986 // direction contributes
2987 splatcolor[ 8] = splatcolor[0] * max(0.0f, dir[0]);
2988 splatcolor[ 9] = splatcolor[0] * max(0.0f, dir[1]);
2989 splatcolor[10] = splatcolor[0] * max(0.0f, dir[2]);
2990 splatcolor[11] = 0.0f;
2991 splatcolor[12] = splatcolor[1] * max(0.0f, dir[0]);
2992 splatcolor[13] = splatcolor[1] * max(0.0f, dir[1]);
2993 splatcolor[14] = splatcolor[1] * max(0.0f, dir[2]);
2994 splatcolor[15] = 0.0f;
2995 splatcolor[16] = splatcolor[2] * max(0.0f, dir[0]);
2996 splatcolor[17] = splatcolor[2] * max(0.0f, dir[1]);
2997 splatcolor[18] = splatcolor[2] * max(0.0f, dir[2]);
2998 splatcolor[19] = 0.0f;
2999 // and do the same for negative directions
3000 splatcolor[20] = splatcolor[0] * max(0.0f, -dir[0]);
3001 splatcolor[21] = splatcolor[0] * max(0.0f, -dir[1]);
3002 splatcolor[22] = splatcolor[0] * max(0.0f, -dir[2]);
3003 splatcolor[23] = 0.0f;
3004 splatcolor[24] = splatcolor[1] * max(0.0f, -dir[0]);
3005 splatcolor[25] = splatcolor[1] * max(0.0f, -dir[1]);
3006 splatcolor[26] = splatcolor[1] * max(0.0f, -dir[2]);
3007 splatcolor[27] = 0.0f;
3008 splatcolor[28] = splatcolor[2] * max(0.0f, -dir[0]);
3009 splatcolor[29] = splatcolor[2] * max(0.0f, -dir[1]);
3010 splatcolor[30] = splatcolor[2] * max(0.0f, -dir[2]);
3011 splatcolor[31] = 0.0f;
3013 // calculate the number of steps we need to traverse this distance
3014 VectorCopy(splatpath->point, steppos);
3015 VectorCopy(splatpath->step, stepdelta);
3016 numsteps = splatpath->remainingsplats;
3017 lightpathsize_current = splatpath->splatsize_current + 1.0f; // add 1.0 for the gradient fade around the sphere
3018 lightpathsize_perstep = splatpath->splatsize_perstep;
3019 for (step = 0;step < numsteps;step++)
3021 // the middle row/column/layer of each splat are full intensity
3024 if (lightpathsize_current > MAXBOUNCEGRIDSPLATSIZE)
3025 lightpathsize_current = MAXBOUNCEGRIDSPLATSIZE;
3026 splatmins[0] = max(1.0f, steppos[0] - lightpathsize_current * 0.5f);
3027 splatmins[1] = max(1.0f, steppos[1] - lightpathsize_current * 0.5f);
3028 splatmins[2] = max(1.0f, steppos[2] - lightpathsize_current * 0.5f);
3029 splatmaxs[0] = min(steppos[0] + lightpathsize_current * 0.5f, resolution[0] - 1.0f);
3030 splatmaxs[1] = min(steppos[1] + lightpathsize_current * 0.5f, resolution[1] - 1.0f);
3031 splatmaxs[2] = min(steppos[2] + lightpathsize_current * 0.5f, resolution[2] - 1.0f);
3032 if (splatmaxs[0] > splatmins[0] && splatmaxs[1] > splatmins[1] && splatmaxs[2] > splatmins[2])
3034 // it is within bounds... do the real work now
3035 int xi, yi, zi, band, row;
3039 float colorscale = 1.0f / lightpathsize_current;
3040 r_refdef.stats[r_stat_bouncegrid_splats]++;
3041 // accumulate light onto the pixels
3042 for (zi = (int)floor(splatmins[2]);zi < splatmaxs[2];zi++)
3044 pixelpos[2] = zi + 0.5f;
3045 for (yi = (int)floor(splatmins[1]); yi < splatmaxs[1]; yi++)
3047 pixelpos[1] = yi + 0.5f;
3048 row = (zi*resolution[1] + yi)*resolution[0];
3049 for (xi = (int)floor(splatmins[0]); xi < splatmaxs[0]; xi++)
3051 pixelpos[0] = xi + 0.5f;
3052 // simple radial antialiased sphere - linear gradient fade over 1 pixel from the edge
3053 w = lightpathsize_current - VectorDistance(pixelpos, steppos);
3059 p = highpixels + 4 * (row + xi);
3060 for (band = 0; band < pixelbands; band++, p += pixelsperband * 4)
3062 // add to the pixel color
3063 p[0] += splatcolor[band * 4 + 0] * w;
3064 p[1] += splatcolor[band * 4 + 1] * w;
3065 p[2] += splatcolor[band * 4 + 2] * w;
3066 p[3] += splatcolor[band * 4 + 3] * w;
3073 VectorAdd(steppos, stepdelta, steppos);
3074 lightpathsize_current += lightpathsize_perstep;
3079 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
3081 const float *inpixel;
3083 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
3086 unsigned int x, y, z;
3087 unsigned int resolution[3];
3088 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3089 for (pixelband = 0;pixelband < pixelbands;pixelband++)
3091 for (z = 1;z < resolution[2]-1;z++)
3093 for (y = 1;y < resolution[1]-1;y++)
3096 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3097 inpixel = inpixels + 4*index;
3098 outpixel = outpixels + 4*index;
3099 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
3101 outpixel[0] = (inpixel[0] + inpixel[ off] + inpixel[0-off]) * (1.0f / 3.0);
3102 outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
3103 outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
3104 outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
3111 static void R_Shadow_BounceGrid_BlurPixels(void)
3114 unsigned int resolution[3];
3116 if (!r_shadow_bouncegrid_state.settings.blur)
3119 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3121 pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3122 pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
3123 pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3124 pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
3127 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
3129 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
3131 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
3133 // toggle the state, highpixels now points to pixels[3] result
3134 r_shadow_bouncegrid_state.highpixels_index ^= 1;
3135 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3138 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
3140 int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
3141 unsigned char *pixelsbgra8 = NULL;
3142 unsigned char *pixelbgra8;
3143 unsigned short *pixelsrgba16f = NULL;
3144 unsigned short *pixelrgba16f;
3145 float *pixelsrgba32f = NULL;
3146 float *highpixels = r_shadow_bouncegrid_state.highpixels;
3149 unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
3150 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
3151 unsigned int pixelband;
3152 unsigned int x, y, z;
3153 unsigned int index, bandindex;
3154 unsigned int resolution[3];
3156 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3158 if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
3160 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3161 r_shadow_bouncegrid_state.texture = NULL;
3164 // if bentnormals exist, we need to normalize and bias them for the shader
3168 for (z = 0;z < resolution[2]-1;z++)
3170 for (y = 0;y < resolution[1]-1;y++)
3173 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3174 highpixel = highpixels + 4*index;
3175 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3177 // only convert pixels that were hit by photons
3178 if (highpixel[3] != 0.0f)
3179 VectorNormalize(highpixel);
3180 VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
3181 highpixel[pixelsperband * 4 + 3] = 1.0f;
3187 // start by clearing the pixels array - we won't be writing to all of it
3189 // then process only the pixels that have at least some color, skipping
3190 // the higher bands for speed on pixels that are black
3191 switch (floatcolors)
3194 if (r_shadow_bouncegrid_state.u8pixels == NULL)
3195 r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
3196 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
3197 for (pixelband = 0;pixelband < pixelbands;pixelband++)
3200 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
3202 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
3204 for (z = 1;z < resolution[2]-1;z++)
3206 for (y = 1;y < resolution[1]-1;y++)
3210 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3211 highpixel = highpixels + 4*index;
3212 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3214 // only convert pixels that were hit by photons
3215 if (VectorLength2(highpixel))
3217 // normalize the bentnormal now
3220 VectorNormalize(highpixel + pixelsperband * 4);
3221 highpixel[pixelsperband * 4 + 3] = 1.0f;
3223 // process all of the pixelbands for this pixel
3224 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3226 pixelbgra8 = pixelsbgra8 + 4*bandindex;
3227 bandpixel = highpixels + 4*bandindex;
3228 c[0] = (int)(bandpixel[0]*256.0f);
3229 c[1] = (int)(bandpixel[1]*256.0f);
3230 c[2] = (int)(bandpixel[2]*256.0f);
3231 c[3] = (int)(bandpixel[3]*256.0f);
3232 pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
3233 pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
3234 pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
3235 pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
3242 if (!r_shadow_bouncegrid_state.createtexture)
3243 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3245 r_shadow_bouncegrid_state.texture = R_LoadTexture3D(r_shadow_texturepool, "bouncegrid", resolution[0], resolution[1], resolution[2]*pixelbands, pixelsbgra8, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, 0, NULL);
3248 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
3249 r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3250 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
3251 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3252 for (z = 1;z < resolution[2]-1;z++)
3254 for (y = 1;y < resolution[1]-1;y++)
3258 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3259 highpixel = highpixels + 4*index;
3260 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3262 // only convert pixels that were hit by photons
3263 if (VectorLength2(highpixel))
3265 // process all of the pixelbands for this pixel
3266 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3268 // time to have fun with IEEE 754 bit hacking...
3271 unsigned int raw[4];
3273 pixelrgba16f = pixelsrgba16f + 4*bandindex;
3274 bandpixel = highpixels + 4*bandindex;
3275 VectorCopy4(bandpixel, u.f);
3276 VectorCopy4(u.raw, c);
3277 // this math supports negative numbers, snaps denormals to zero
3278 //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
3279 //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
3280 //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
3281 //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
3282 // this math does not support negative
3283 pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
3284 pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
3285 pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
3286 pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
3293 if (!r_shadow_bouncegrid_state.createtexture)
3294 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3296 r_shadow_bouncegrid_state.texture = R_LoadTexture3D(r_shadow_texturepool, "bouncegrid", resolution[0], resolution[1], resolution[2]*pixelbands, (const unsigned char *)pixelsrgba16f, TEXTYPE_COLORBUFFER16F, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, 0, NULL);
3299 // our native format happens to match, so this is easy.
3300 pixelsrgba32f = highpixels;
3302 if (!r_shadow_bouncegrid_state.createtexture)
3303 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3305 r_shadow_bouncegrid_state.texture = R_LoadTexture3D(r_shadow_texturepool, "bouncegrid", resolution[0], resolution[1], resolution[2]*pixelbands, (const unsigned char *)pixelsrgba32f, TEXTYPE_COLORBUFFER32F, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, 0, NULL);
3309 r_shadow_bouncegrid_state.lastupdatetime = realtime;
3312 static void R_Shadow_BounceGrid_TracePhotons(r_shadow_bouncegrid_settings_t settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
3314 vec3_t bouncerandom[10];
3317 int hitsupercontentsmask;
3318 int skipsupercontentsmask;
3322 float bounceminimumintensity2;
3324 //trace_t cliptrace2;
3325 //trace_t cliptrace3;
3326 unsigned int lightindex;
3328 randomseed_t randomseed;
3330 vec3_t baseshotcolor;
3336 vec_t distancetraveled;
3340 // compute a seed for the unstable random modes
3341 Math_RandomSeed_FromInts(&randomseed, 0, 0, 0, realtime * 1000.0);
3342 seed = realtime * 1000.0;
3344 r_shadow_bouncegrid_state.numsplatpaths = 0;
3346 // figure out what we want to interact with
3347 if (settings.hitmodels)
3348 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;// | SUPERCONTENTS_LIQUIDSMASK;
3350 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
3351 skipsupercontentsmask = SUPERCONTENTS_SKY; // this allows the e1m5 sky shadow to work by ignoring the sky surfaces
3352 maxbounce = settings.maxbounce;
3354 for (lightindex = 0;lightindex < range2;lightindex++)
3356 if (lightindex < range)
3358 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3361 rtlight = &light->rtlight;
3364 rtlight = r_refdef.scene.lights[lightindex - range];
3365 // note that this code used to keep track of residual photons and
3366 // distribute them evenly to achieve exactly a desired photon count,
3367 // but that caused unwanted flickering in dynamic mode
3368 shootparticles = (int)floor(rtlight->bouncegrid_photons);
3369 // skip if we won't be shooting any photons
3370 if (!shootparticles)
3372 radius = rtlight->radius * settings.lightradiusscale;
3373 //s = settings.particleintensity / shootparticles;
3374 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
3375 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
3376 if (VectorLength2(baseshotcolor) <= 0.0f)
3378 r_refdef.stats[r_stat_bouncegrid_lights]++;
3379 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
3380 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
3381 bounceminimumintensity2 = VectorLength(baseshotcolor) * settings.bounceminimumintensity2;
3383 // for seeded random we start the RNG with the position of the light
3384 if (settings.rng_seed >= 0)
3392 u.f[0] = rtlight->shadoworigin[0];
3393 u.f[1] = rtlight->shadoworigin[1];
3394 u.f[2] = rtlight->shadoworigin[2];
3396 switch (settings.rng_type)
3400 // we have to shift the seed provided by the user because the result must be odd
3401 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3] ^ (settings.rng_seed << 1));
3404 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3] ^ settings.rng_seed;
3409 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
3411 VectorCopy(baseshotcolor, shotcolor);
3412 VectorCopy(rtlight->shadoworigin, clipstart);
3413 switch (settings.rng_type)
3417 VectorLehmerRandom(&randomseed, clipend);
3418 if (settings.bounceanglediffuse)
3420 // we want random to be stable, so we still have to do all the random we would have done
3421 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3422 VectorLehmerRandom(&randomseed, bouncerandom[bouncecount]);
3426 VectorCheeseRandom(seed, clipend);
3427 if (settings.bounceanglediffuse)
3429 // we want random to be stable, so we still have to do all the random we would have done
3430 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3431 VectorCheeseRandom(seed, bouncerandom[bouncecount]);
3436 // we want a uniform distribution spherically, not merely within the sphere
3437 if (settings.normalizevectors)
3438 VectorNormalize(clipend);
3440 VectorMA(clipstart, radius, clipend, clipend);
3441 distancetraveled = 0.0f;
3442 for (bouncecount = 0;;bouncecount++)
3444 r_refdef.stats[r_stat_bouncegrid_traces]++;
3445 rtlight->bouncegrid_traces++;
3446 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
3447 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
3448 if (settings.staticmode || settings.rng_seed < 0)
3450 // static mode fires a LOT of rays but none of them are identical, so they are not cached
3451 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
3452 cliptrace = CL_TraceLine(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), NULL, hitsupercontentsmask, skipsupercontentsmask, collision_extendmovelength.value, true, false, NULL, true, true);
3456 // dynamic mode fires many rays and most will match the cache from the previous frame
3457 cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask, skipsupercontentsmask);
3459 if (bouncecount > 0 || settings.includedirectlighting)
3462 VectorCopy(cliptrace.endpos, hitpos);
3463 R_Shadow_BounceGrid_AddSplatPath(clipstart, hitpos, shotcolor, distancetraveled);
3465 distancetraveled += VectorDistance(clipstart, cliptrace.endpos);
3466 s = VectorDistance(rtlight->shadoworigin, cliptrace.endpos);
3467 if (rtlight->bouncegrid_effectiveradius < s)
3468 rtlight->bouncegrid_effectiveradius = s;
3469 if (cliptrace.fraction >= 1.0f)
3471 r_refdef.stats[r_stat_bouncegrid_hits]++;
3472 rtlight->bouncegrid_hits++;
3473 if (bouncecount >= maxbounce)
3475 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
3476 // also clamp the resulting color to never add energy, even if the user requests extreme values
3477 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
3478 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
3480 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
3481 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
3482 surfcolor[0] = min(surfcolor[0], 1.0f);
3483 surfcolor[1] = min(surfcolor[1], 1.0f);
3484 surfcolor[2] = min(surfcolor[2], 1.0f);
3485 VectorMultiply(shotcolor, surfcolor, shotcolor);
3486 if (VectorLength2(shotcolor) <= bounceminimumintensity2)
3488 r_refdef.stats[r_stat_bouncegrid_bounces]++;
3489 if (settings.bounceanglediffuse)
3491 // random direction, primarily along plane normal
3492 s = VectorDistance(cliptrace.endpos, clipend);
3493 VectorMA(cliptrace.plane.normal, 0.95f, bouncerandom[bouncecount], clipend);
3494 VectorNormalize(clipend);
3495 VectorScale(clipend, s, clipend);
3499 // reflect the remaining portion of the line across plane normal
3500 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
3501 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
3503 // calculate the new line start and end
3504 VectorCopy(cliptrace.endpos, clipstart);
3505 VectorAdd(clipstart, clipend, clipend);
3511 void R_Shadow_UpdateBounceGridTexture(void)
3513 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3514 r_shadow_bouncegrid_settings_t settings;
3515 qboolean enable = false;
3516 qboolean settingschanged;
3517 unsigned int range; // number of world lights
3518 unsigned int range1; // number of dynamic lights (or zero if disabled)
3519 unsigned int range2; // range+range1
3521 enable = R_Shadow_BounceGrid_CheckEnable(flag);
3523 R_Shadow_BounceGrid_GenerateSettings(&settings);
3525 // changing intensity does not require an update
3526 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
3528 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
3530 // when settings change, we free everything as it is just simpler that way.
3531 if (settingschanged || !enable)
3533 // not enabled, make sure we free anything we don't need anymore.
3534 if (r_shadow_bouncegrid_state.texture)
3536 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3537 r_shadow_bouncegrid_state.texture = NULL;
3539 r_shadow_bouncegrid_state.highpixels = NULL;
3540 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
3541 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
3542 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
3543 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
3544 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
3545 r_shadow_bouncegrid_state.maxsplatpaths = 0;
3546 r_shadow_bouncegrid_state.numpixels = 0;
3547 r_shadow_bouncegrid_state.directional = false;
3553 // if all the settings seem identical to the previous update, return
3554 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
3557 // store the new settings
3558 r_shadow_bouncegrid_state.settings = settings;
3560 R_Shadow_BounceGrid_UpdateSpacing();
3562 // get the range of light numbers we'll be looping over:
3563 // range = static lights
3564 // range1 = dynamic lights (optional)
3565 // range2 = range + range1
3566 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3567 range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
3568 range2 = range + range1;
3570 // calculate weighting factors for distributing photons among the lights
3571 R_Shadow_BounceGrid_AssignPhotons(&settings, range, range1, range2, flag);
3573 // trace the photons from lights and accumulate illumination
3574 R_Shadow_BounceGrid_TracePhotons(settings, range, range1, range2, flag);
3576 // clear the texture
3577 R_Shadow_BounceGrid_ClearPixels();
3579 // accumulate the light splatting into texture
3580 R_Shadow_BounceGrid_PerformSplats();
3582 // apply a mild blur filter to the texture
3583 R_Shadow_BounceGrid_BlurPixels();
3585 // convert the pixels to lower precision and upload the texture
3586 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
3588 // after we compute the static lighting we don't need to keep the highpixels array around
3589 if (settings.staticmode)
3591 r_shadow_bouncegrid_state.highpixels = NULL;
3592 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
3593 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
3594 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
3595 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
3596 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
3597 r_shadow_bouncegrid_state.maxsplatpaths = 0;
3601 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
3603 R_Shadow_RenderMode_Reset();
3604 GL_BlendFunc(GL_ONE, GL_ONE);
3605 GL_DepthRange(0, 1);
3606 GL_DepthTest(r_showshadowvolumes.integer < 2);
3607 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
3608 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
3609 GL_CullFace(GL_NONE);
3610 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
3613 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
3615 R_Shadow_RenderMode_Reset();
3616 GL_BlendFunc(GL_ONE, GL_ONE);
3617 GL_DepthRange(0, 1);
3618 GL_DepthTest(r_showlighting.integer < 2);
3619 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
3621 GL_DepthFunc(GL_EQUAL);
3622 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
3623 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
3626 void R_Shadow_RenderMode_End(void)
3628 R_Shadow_RenderMode_Reset();
3629 R_Shadow_RenderMode_ActiveLight(NULL);
3631 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3632 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3635 int bboxedges[12][2] =
3654 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
3656 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
3658 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
3659 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
3660 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
3661 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
3664 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
3665 return true; // invisible
3666 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
3667 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
3668 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
3669 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
3670 r_refdef.stats[r_stat_lights_scissored]++;
3674 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
3677 const float *vertex3f;
3678 const float *normal3f;
3680 float dist, dot, distintensity, shadeintensity, v[3], n[3];
3681 switch (r_shadow_rendermode)
3683 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3684 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3685 if (VectorLength2(diffusecolor) > 0)
3687 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)
3689 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3690 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3691 if ((dot = DotProduct(n, v)) < 0)
3693 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3694 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
3697 VectorCopy(ambientcolor, color4f);
3698 if (r_refdef.fogenabled)
3701 f = RSurf_FogVertex(vertex3f);
3702 VectorScale(color4f, f, color4f);
3709 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3711 VectorCopy(ambientcolor, color4f);
3712 if (r_refdef.fogenabled)
3715 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3716 f = RSurf_FogVertex(vertex3f);
3717 VectorScale(color4f + 4*i, f, color4f);
3723 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3724 if (VectorLength2(diffusecolor) > 0)
3726 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)
3728 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3729 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3731 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3732 if ((dot = DotProduct(n, v)) < 0)
3734 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3735 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3736 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3737 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3741 color4f[0] = ambientcolor[0] * distintensity;
3742 color4f[1] = ambientcolor[1] * distintensity;
3743 color4f[2] = ambientcolor[2] * distintensity;
3745 if (r_refdef.fogenabled)
3748 f = RSurf_FogVertex(vertex3f);
3749 VectorScale(color4f, f, color4f);
3753 VectorClear(color4f);
3759 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3761 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3762 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3764 color4f[0] = ambientcolor[0] * distintensity;
3765 color4f[1] = ambientcolor[1] * distintensity;
3766 color4f[2] = ambientcolor[2] * distintensity;
3767 if (r_refdef.fogenabled)
3770 f = RSurf_FogVertex(vertex3f);
3771 VectorScale(color4f, f, color4f);
3775 VectorClear(color4f);
3780 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3781 if (VectorLength2(diffusecolor) > 0)
3783 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)
3785 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3786 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3788 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3789 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3790 if ((dot = DotProduct(n, v)) < 0)
3792 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3793 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3794 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3795 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3799 color4f[0] = ambientcolor[0] * distintensity;
3800 color4f[1] = ambientcolor[1] * distintensity;
3801 color4f[2] = ambientcolor[2] * distintensity;
3803 if (r_refdef.fogenabled)
3806 f = RSurf_FogVertex(vertex3f);
3807 VectorScale(color4f, f, color4f);
3811 VectorClear(color4f);
3817 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3819 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3820 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3822 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3823 color4f[0] = ambientcolor[0] * distintensity;
3824 color4f[1] = ambientcolor[1] * distintensity;
3825 color4f[2] = ambientcolor[2] * distintensity;
3826 if (r_refdef.fogenabled)
3829 f = RSurf_FogVertex(vertex3f);
3830 VectorScale(color4f, f, color4f);
3834 VectorClear(color4f);
3844 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3846 // used to display how many times a surface is lit for level design purposes
3847 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3848 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3852 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
3854 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3855 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
3859 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3866 int newnumtriangles;
3870 int maxtriangles = 1024;
3871 int newelements[1024*3];
3872 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3873 for (renders = 0;renders < 4;renders++)
3878 newnumtriangles = 0;
3880 // due to low fillrate on the cards this vertex lighting path is
3881 // designed for, we manually cull all triangles that do not
3882 // contain a lit vertex
3883 // this builds batches of triangles from multiple surfaces and
3884 // renders them at once
3885 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3887 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3889 if (newnumtriangles)
3891 newfirstvertex = min(newfirstvertex, e[0]);
3892 newlastvertex = max(newlastvertex, e[0]);
3896 newfirstvertex = e[0];
3897 newlastvertex = e[0];
3899 newfirstvertex = min(newfirstvertex, e[1]);
3900 newlastvertex = max(newlastvertex, e[1]);
3901 newfirstvertex = min(newfirstvertex, e[2]);
3902 newlastvertex = max(newlastvertex, e[2]);
3908 if (newnumtriangles >= maxtriangles)
3910 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3911 newnumtriangles = 0;
3917 if (newnumtriangles >= 1)
3919 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3922 // if we couldn't find any lit triangles, exit early
3925 // now reduce the intensity for the next overbright pass
3926 // we have to clamp to 0 here incase the drivers have improper
3927 // handling of negative colors
3928 // (some old drivers even have improper handling of >1 color)
3930 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3932 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3934 c[0] = max(0, c[0] - 1);
3935 c[1] = max(0, c[1] - 1);
3936 c[2] = max(0, c[2] - 1);
3948 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
3950 // OpenGL 1.1 path (anything)
3951 float ambientcolorbase[3], diffusecolorbase[3];
3952 float ambientcolorpants[3], diffusecolorpants[3];
3953 float ambientcolorshirt[3], diffusecolorshirt[3];
3954 const float *surfacecolor = rsurface.texture->dlightcolor;
3955 const float *surfacepants = rsurface.colormap_pantscolor;
3956 const float *surfaceshirt = rsurface.colormap_shirtcolor;
3957 rtexture_t *basetexture = rsurface.texture->basetexture;
3958 rtexture_t *pantstexture = rsurface.texture->pantstexture;
3959 rtexture_t *shirttexture = rsurface.texture->shirttexture;
3960 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3961 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3962 ambientscale *= 2 * r_refdef.view.colorscale;
3963 diffusescale *= 2 * r_refdef.view.colorscale;
3964 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3965 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3966 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3967 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3968 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3969 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
3970 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3971 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
3972 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3973 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
3974 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
3975 R_Mesh_TexBind(0, basetexture);
3976 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
3977 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
3978 switch(r_shadow_rendermode)
3980 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3981 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
3982 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3983 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3984 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3986 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3987 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
3988 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
3989 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
3990 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3992 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3993 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
3994 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3995 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3996 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3998 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
4003 //R_Mesh_TexBind(0, basetexture);
4004 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
4007 R_Mesh_TexBind(0, pantstexture);
4008 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
4012 R_Mesh_TexBind(0, shirttexture);
4013 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
4017 extern cvar_t gl_lightmaps;
4018 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
4020 float ambientscale, diffusescale, specularscale;
4022 float lightcolor[3];
4023 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
4024 ambientscale = rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient;
4025 diffusescale = rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient);
4026 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
4027 if (!r_shadow_usenormalmap.integer)
4029 ambientscale += 1.0f * diffusescale;
4033 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
4035 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
4038 VectorNegate(lightcolor, lightcolor);
4039 GL_BlendEquationSubtract(true);
4041 RSurf_SetupDepthAndCulling();
4042 switch (r_shadow_rendermode)
4044 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
4045 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
4046 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
4048 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
4049 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
4051 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
4052 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
4053 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
4054 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
4055 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
4058 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
4062 GL_BlendEquationSubtract(false);
4065 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)
4067 matrix4x4_t tempmatrix = *matrix;
4068 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
4070 // if this light has been compiled before, free the associated data
4071 R_RTLight_Uncompile(rtlight);
4073 // clear it completely to avoid any lingering data
4074 memset(rtlight, 0, sizeof(*rtlight));
4076 // copy the properties
4077 rtlight->matrix_lighttoworld = tempmatrix;
4078 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
4079 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
4080 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
4081 VectorCopy(color, rtlight->color);
4082 rtlight->cubemapname[0] = 0;
4083 if (cubemapname && cubemapname[0])
4084 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
4085 rtlight->shadow = shadow;
4086 rtlight->corona = corona;
4087 rtlight->style = style;
4088 rtlight->isstatic = isstatic;
4089 rtlight->coronasizescale = coronasizescale;
4090 rtlight->ambientscale = ambientscale;
4091 rtlight->diffusescale = diffusescale;
4092 rtlight->specularscale = specularscale;
4093 rtlight->flags = flags;
4095 // compute derived data
4096 //rtlight->cullradius = rtlight->radius;
4097 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
4098 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
4099 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
4100 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
4101 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
4102 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
4103 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
4106 // compiles rtlight geometry
4107 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
4108 void R_RTLight_Compile(rtlight_t *rtlight)
4111 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
4112 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
4113 entity_render_t *ent = r_refdef.scene.worldentity;
4114 dp_model_t *model = r_refdef.scene.worldmodel;
4115 unsigned char *data;
4118 // compile the light
4119 rtlight->compiled = true;
4120 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
4121 rtlight->static_numleafs = 0;
4122 rtlight->static_numleafpvsbytes = 0;
4123 rtlight->static_leaflist = NULL;
4124 rtlight->static_leafpvs = NULL;
4125 rtlight->static_numsurfaces = 0;
4126 rtlight->static_surfacelist = NULL;
4127 rtlight->static_shadowmap_receivers = 0x3F;
4128 rtlight->static_shadowmap_casters = 0x3F;
4129 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
4130 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
4131 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
4132 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
4133 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
4134 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
4136 if (model && model->GetLightInfo)
4138 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
4139 r_shadow_compilingrtlight = rtlight;
4140 R_FrameData_SetMark();
4141 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);
4142 R_FrameData_ReturnToMark();
4143 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
4144 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
4145 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
4146 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
4147 rtlight->static_numsurfaces = numsurfaces;
4148 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
4149 rtlight->static_numleafs = numleafs;
4150 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
4151 rtlight->static_numleafpvsbytes = numleafpvsbytes;
4152 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
4153 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
4154 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
4155 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
4156 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
4157 if (rtlight->static_numsurfaces)
4158 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
4159 if (rtlight->static_numleafs)
4160 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
4161 if (rtlight->static_numleafpvsbytes)
4162 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
4163 if (rtlight->static_numshadowtrispvsbytes)
4164 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
4165 if (rtlight->static_numlighttrispvsbytes)
4166 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
4167 R_FrameData_SetMark();
4168 switch (rtlight->shadowmode)
4170 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4171 if (model->CompileShadowMap && rtlight->shadow)
4172 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
4175 if (model->CompileShadowVolume && rtlight->shadow)
4176 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
4179 R_FrameData_ReturnToMark();
4180 // now we're done compiling the rtlight
4181 r_shadow_compilingrtlight = NULL;
4185 // use smallest available cullradius - box radius or light radius
4186 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
4187 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
4189 shadowzpasstris = 0;
4190 if (rtlight->static_meshchain_shadow_zpass)
4191 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
4192 shadowzpasstris += mesh->numtriangles;
4194 shadowzfailtris = 0;
4195 if (rtlight->static_meshchain_shadow_zfail)
4196 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
4197 shadowzfailtris += mesh->numtriangles;
4200 if (rtlight->static_numlighttrispvsbytes)
4201 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
4202 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
4206 if (rtlight->static_numshadowtrispvsbytes)
4207 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
4208 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
4211 if (developer_extra.integer)
4212 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);
4215 void R_RTLight_Uncompile(rtlight_t *rtlight)
4217 if (rtlight->compiled)
4219 if (rtlight->static_meshchain_shadow_zpass)
4220 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
4221 rtlight->static_meshchain_shadow_zpass = NULL;
4222 if (rtlight->static_meshchain_shadow_zfail)
4223 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
4224 rtlight->static_meshchain_shadow_zfail = NULL;
4225 if (rtlight->static_meshchain_shadow_shadowmap)
4226 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
4227 rtlight->static_meshchain_shadow_shadowmap = NULL;
4228 // these allocations are grouped
4229 if (rtlight->static_surfacelist)
4230 Mem_Free(rtlight->static_surfacelist);
4231 rtlight->static_numleafs = 0;
4232 rtlight->static_numleafpvsbytes = 0;
4233 rtlight->static_leaflist = NULL;
4234 rtlight->static_leafpvs = NULL;
4235 rtlight->static_numsurfaces = 0;
4236 rtlight->static_surfacelist = NULL;
4237 rtlight->static_numshadowtrispvsbytes = 0;
4238 rtlight->static_shadowtrispvs = NULL;
4239 rtlight->static_numlighttrispvsbytes = 0;
4240 rtlight->static_lighttrispvs = NULL;
4241 rtlight->compiled = false;
4245 void R_Shadow_UncompileWorldLights(void)
4249 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4250 for (lightindex = 0;lightindex < range;lightindex++)
4252 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4255 R_RTLight_Uncompile(&light->rtlight);
4259 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
4263 // reset the count of frustum planes
4264 // see rtlight->cached_frustumplanes definition for how much this array
4266 rtlight->cached_numfrustumplanes = 0;
4268 if (r_trippy.integer)
4271 // haven't implemented a culling path for ortho rendering
4272 if (!r_refdef.view.useperspective)
4274 // check if the light is on screen and copy the 4 planes if it is
4275 for (i = 0;i < 4;i++)
4276 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4279 for (i = 0;i < 4;i++)
4280 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4285 // generate a deformed frustum that includes the light origin, this is
4286 // used to cull shadow casting surfaces that can not possibly cast a
4287 // shadow onto the visible light-receiving surfaces, which can be a
4290 // if the light origin is onscreen the result will be 4 planes exactly
4291 // if the light origin is offscreen on only one axis the result will
4292 // be exactly 5 planes (split-side case)
4293 // if the light origin is offscreen on two axes the result will be
4294 // exactly 4 planes (stretched corner case)
4295 for (i = 0;i < 4;i++)
4297 // quickly reject standard frustum planes that put the light
4298 // origin outside the frustum
4299 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4302 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4304 // if all the standard frustum planes were accepted, the light is onscreen
4305 // otherwise we need to generate some more planes below...
4306 if (rtlight->cached_numfrustumplanes < 4)
4308 // at least one of the stock frustum planes failed, so we need to
4309 // create one or two custom planes to enclose the light origin
4310 for (i = 0;i < 4;i++)
4312 // create a plane using the view origin and light origin, and a
4313 // single point from the frustum corner set
4314 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
4315 VectorNormalize(plane.normal);
4316 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
4317 // see if this plane is backwards and flip it if so
4318 for (j = 0;j < 4;j++)
4319 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4323 VectorNegate(plane.normal, plane.normal);
4325 // flipped plane, test again to see if it is now valid
4326 for (j = 0;j < 4;j++)
4327 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4329 // if the plane is still not valid, then it is dividing the
4330 // frustum and has to be rejected
4334 // we have created a valid plane, compute extra info
4335 PlaneClassify(&plane);
4337 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4339 // if we've found 5 frustum planes then we have constructed a
4340 // proper split-side case and do not need to keep searching for
4341 // planes to enclose the light origin
4342 if (rtlight->cached_numfrustumplanes == 5)
4350 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
4352 plane = rtlight->cached_frustumplanes[i];
4353 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));
4358 // now add the light-space box planes if the light box is rotated, as any
4359 // caster outside the oriented light box is irrelevant (even if it passed
4360 // the worldspace light box, which is axial)
4361 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
4363 for (i = 0;i < 6;i++)
4367 v[i >> 1] = (i & 1) ? -1 : 1;
4368 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
4369 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
4370 plane.dist = VectorNormalizeLength(plane.normal);
4371 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
4372 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4378 // add the world-space reduced box planes
4379 for (i = 0;i < 6;i++)
4381 VectorClear(plane.normal);
4382 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
4383 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
4384 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4393 // reduce all plane distances to tightly fit the rtlight cull box, which
4395 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4396 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4397 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4398 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4399 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4400 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4401 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4402 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4403 oldnum = rtlight->cached_numfrustumplanes;
4404 rtlight->cached_numfrustumplanes = 0;
4405 for (j = 0;j < oldnum;j++)
4407 // find the nearest point on the box to this plane
4408 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
4409 for (i = 1;i < 8;i++)
4411 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
4412 if (bestdist > dist)
4415 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);
4416 // if the nearest point is near or behind the plane, we want this
4417 // plane, otherwise the plane is useless as it won't cull anything
4418 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
4420 PlaneClassify(&rtlight->cached_frustumplanes[j]);
4421 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
4428 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
4432 RSurf_ActiveWorldEntity();
4434 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4437 GL_CullFace(GL_NONE);
4438 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
4439 for (;mesh;mesh = mesh->next)
4441 if (!mesh->sidetotals[r_shadow_shadowmapside])
4443 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
4444 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4445 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);
4449 else if (r_refdef.scene.worldentity->model)
4450 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);
4452 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4455 static void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
4457 qboolean zpass = false;
4460 int surfacelistindex;
4461 msurface_t *surface;
4463 // if triangle neighbors are disabled, shadowvolumes are disabled
4464 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
4467 RSurf_ActiveWorldEntity();
4469 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4472 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
4474 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
4475 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
4477 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
4478 for (;mesh;mesh = mesh->next)
4480 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->numtriangles;
4481 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4482 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
4484 // increment stencil if frontface is infront of depthbuffer
4485 GL_CullFace(r_refdef.view.cullface_back);
4486 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
4487 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);
4488 // decrement stencil if backface is infront of depthbuffer
4489 GL_CullFace(r_refdef.view.cullface_front);
4490 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
4492 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
4494 // decrement stencil if backface is behind depthbuffer
4495 GL_CullFace(r_refdef.view.cullface_front);
4496 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
4497 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);
4498 // increment stencil if frontface is behind depthbuffer
4499 GL_CullFace(r_refdef.view.cullface_back);
4500 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
4502 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);
4506 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
4508 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
4509 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
4510 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
4512 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
4513 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
4514 if (CHECKPVSBIT(trispvs, t))
4515 shadowmarklist[numshadowmark++] = t;
4517 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);
4519 else if (numsurfaces)
4521 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);
4524 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4527 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
4529 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
4530 vec_t relativeshadowradius;
4531 RSurf_ActiveModelEntity(ent, false, false, false);
4532 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
4533 // we need to re-init the shader for each entity because the matrix changed
4534 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
4535 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
4536 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
4537 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
4538 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
4539 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
4540 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
4541 switch (r_shadow_rendermode)
4543 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
4544 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4547 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4550 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4553 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
4555 // set up properties for rendering light onto this entity
4556 RSurf_ActiveModelEntity(ent, true, true, false);
4557 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
4558 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4559 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4560 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4563 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
4565 if (!r_refdef.scene.worldmodel->DrawLight)
4568 // set up properties for rendering light onto this entity
4569 RSurf_ActiveWorldEntity();
4570 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
4571 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4572 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4573 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4575 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
4577 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4580 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
4582 dp_model_t *model = ent->model;
4583 if (!model->DrawLight)
4586 R_Shadow_SetupEntityLight(ent);
4588 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
4590 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4593 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
4597 int numleafs, numsurfaces;
4598 int *leaflist, *surfacelist;
4599 unsigned char *leafpvs;
4600 unsigned char *shadowtrispvs;
4601 unsigned char *lighttrispvs;
4602 //unsigned char *surfacesides;
4603 int numlightentities;
4604 int numlightentities_noselfshadow;
4605 int numshadowentities;
4606 int numshadowentities_noselfshadow;
4607 // FIXME: bounds check lightentities and shadowentities, etc.
4608 static entity_render_t *lightentities[MAX_EDICTS];
4609 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
4610 static entity_render_t *shadowentities[MAX_EDICTS];
4611 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
4613 qboolean castshadows;
4615 rtlight->draw = false;
4616 rtlight->cached_numlightentities = 0;
4617 rtlight->cached_numlightentities_noselfshadow = 0;
4618 rtlight->cached_numshadowentities = 0;
4619 rtlight->cached_numshadowentities_noselfshadow = 0;
4620 rtlight->cached_numsurfaces = 0;
4621 rtlight->cached_lightentities = NULL;
4622 rtlight->cached_lightentities_noselfshadow = NULL;
4623 rtlight->cached_shadowentities = NULL;
4624 rtlight->cached_shadowentities_noselfshadow = NULL;
4625 rtlight->cached_shadowtrispvs = NULL;
4626 rtlight->cached_lighttrispvs = NULL;
4627 rtlight->cached_surfacelist = NULL;
4628 rtlight->shadowmapsidesize = 0;
4630 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
4631 // skip lights that are basically invisible (color 0 0 0)
4632 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
4634 // loading is done before visibility checks because loading should happen
4635 // all at once at the start of a level, not when it stalls gameplay.
4636 // (especially important to benchmarks)
4638 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
4640 if (rtlight->compiled)
4641 R_RTLight_Uncompile(rtlight);
4642 R_RTLight_Compile(rtlight);
4646 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
4648 // look up the light style value at this time
4649 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4650 VectorScale(rtlight->color, f, rtlight->currentcolor);
4652 if (rtlight->selected)
4654 f = 2 + sin(realtime * M_PI * 4.0);
4655 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
4659 // if lightstyle is currently off, don't draw the light
4660 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
4663 // skip processing on corona-only lights
4667 // if the light box is offscreen, skip it
4668 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
4671 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
4672 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
4674 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4676 // don't allow lights to be drawn if using r_shadow_bouncegrid 2, except if we're using static bouncegrid where dynamic lights still need to draw
4677 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
4680 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
4682 // compiled light, world available and can receive realtime lighting
4683 // retrieve leaf information
4684 numleafs = rtlight->static_numleafs;
4685 leaflist = rtlight->static_leaflist;
4686 leafpvs = rtlight->static_leafpvs;
4687 numsurfaces = rtlight->static_numsurfaces;
4688 surfacelist = rtlight->static_surfacelist;
4689 //surfacesides = NULL;
4690 shadowtrispvs = rtlight->static_shadowtrispvs;
4691 lighttrispvs = rtlight->static_lighttrispvs;
4693 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4695 // dynamic light, world available and can receive realtime lighting
4696 // calculate lit surfaces and leafs
4697 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);
4698 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4699 leaflist = r_shadow_buffer_leaflist;
4700 leafpvs = r_shadow_buffer_leafpvs;
4701 surfacelist = r_shadow_buffer_surfacelist;
4702 //surfacesides = r_shadow_buffer_surfacesides;
4703 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4704 lighttrispvs = r_shadow_buffer_lighttrispvs;
4705 // if the reduced leaf bounds are offscreen, skip it
4706 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4717 //surfacesides = NULL;
4718 shadowtrispvs = NULL;
4719 lighttrispvs = NULL;
4721 // check if light is illuminating any visible leafs
4724 for (i = 0; i < numleafs; i++)
4725 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4731 // make a list of lit entities and shadow casting entities
4732 numlightentities = 0;
4733 numlightentities_noselfshadow = 0;
4734 numshadowentities = 0;
4735 numshadowentities_noselfshadow = 0;
4737 // add dynamic entities that are lit by the light
4738 for (i = 0; i < r_refdef.scene.numentities; i++)
4741 entity_render_t *ent = r_refdef.scene.entities[i];
4743 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4745 // skip the object entirely if it is not within the valid
4746 // shadow-casting region (which includes the lit region)
4747 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
4749 if (!(model = ent->model))
4751 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4753 // this entity wants to receive light, is visible, and is
4754 // inside the light box
4755 // TODO: check if the surfaces in the model can receive light
4756 // so now check if it's in a leaf seen by the light
4757 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))
4759 if (ent->flags & RENDER_NOSELFSHADOW)
4760 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
4762 lightentities[numlightentities++] = ent;
4763 // since it is lit, it probably also casts a shadow...
4764 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4765 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4766 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4768 // note: exterior models without the RENDER_NOSELFSHADOW
4769 // flag still create a RENDER_NOSELFSHADOW shadow but
4770 // are lit normally, this means that they are
4771 // self-shadowing but do not shadow other
4772 // RENDER_NOSELFSHADOW entities such as the gun
4773 // (very weird, but keeps the player shadow off the gun)
4774 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4775 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4777 shadowentities[numshadowentities++] = ent;
4780 else if (ent->flags & RENDER_SHADOW)
4782 // this entity is not receiving light, but may still need to
4784 // TODO: check if the surfaces in the model can cast shadow
4785 // now check if it is in a leaf seen by the light
4786 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))
4788 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4789 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4790 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4792 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4793 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4795 shadowentities[numshadowentities++] = ent;
4800 // return if there's nothing at all to light
4801 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4804 // count this light in the r_speeds
4805 r_refdef.stats[r_stat_lights]++;
4807 // flag it as worth drawing later
4808 rtlight->draw = true;
4810 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
4811 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4813 numshadowentities = numshadowentities_noselfshadow = 0;
4814 rtlight->castshadows = castshadows;
4816 // cache all the animated entities that cast a shadow but are not visible
4817 for (i = 0; i < numshadowentities; i++)
4818 R_AnimCache_GetEntity(shadowentities[i], false, false);
4819 for (i = 0; i < numshadowentities_noselfshadow; i++)
4820 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4822 // we can convert noselfshadow to regular if there are no receivers of that type (or we're using r_shadow_deferred which doesn't support noselfshadow anyway)
4823 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
4825 for (i = 0; i < numshadowentities_noselfshadow; i++)
4826 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
4827 numshadowentities_noselfshadow = 0;
4830 // we can convert noselfshadow to regular if there are no casters of that type
4831 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
4833 for (i = 0; i < numlightentities_noselfshadow; i++)
4834 lightentities[numlightentities++] = lightentities_noselfshadow[i];
4835 numlightentities_noselfshadow = 0;
4838 // allocate some temporary memory for rendering this light later in the frame
4839 // reusable buffers need to be copied, static data can be used as-is
4840 rtlight->cached_numlightentities = numlightentities;
4841 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
4842 rtlight->cached_numshadowentities = numshadowentities;
4843 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4844 rtlight->cached_numsurfaces = numsurfaces;
4845 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4846 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4847 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4848 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4849 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4851 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4852 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4853 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4854 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4855 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4859 // compiled light data
4860 rtlight->cached_shadowtrispvs = shadowtrispvs;
4861 rtlight->cached_lighttrispvs = lighttrispvs;
4862 rtlight->cached_surfacelist = surfacelist;
4865 if (R_Shadow_ShadowMappingEnabled())
4867 // figure out the shadowmapping parameters for this light
4868 vec3_t nearestpoint;
4871 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4872 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4873 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4874 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4875 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
4876 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4877 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4878 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4879 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
4883 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
4887 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4888 int numlightentities;
4889 int numlightentities_noselfshadow;
4890 int numshadowentities;
4891 int numshadowentities_noselfshadow;
4892 entity_render_t **lightentities;
4893 entity_render_t **lightentities_noselfshadow;
4894 entity_render_t **shadowentities;
4895 entity_render_t **shadowentities_noselfshadow;
4897 static unsigned char entitysides[MAX_EDICTS];
4898 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4904 matrix4x4_t radiustolight;
4906 // check if we cached this light this frame (meaning it is worth drawing)
4907 if (!rtlight->draw || !rtlight->castshadows)
4910 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
4911 if (rtlight->shadowmapatlassidesize == 0)
4913 rtlight->castshadows = false;
4917 // set up a scissor rectangle for this light
4918 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4921 // don't let sound skip if going slow
4922 if (r_refdef.scene.extraupdate)
4925 numlightentities = rtlight->cached_numlightentities;
4926 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4927 numshadowentities = rtlight->cached_numshadowentities;
4928 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4929 numsurfaces = rtlight->cached_numsurfaces;
4930 lightentities = rtlight->cached_lightentities;
4931 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4932 shadowentities = rtlight->cached_shadowentities;
4933 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4934 shadowtrispvs = rtlight->cached_shadowtrispvs;
4935 lighttrispvs = rtlight->cached_lighttrispvs;
4936 surfacelist = rtlight->cached_surfacelist;
4938 // make this the active rtlight for rendering purposes
4939 R_Shadow_RenderMode_ActiveLight(rtlight);
4941 radiustolight = rtlight->matrix_worldtolight;
4942 Matrix4x4_Abs(&radiustolight);
4944 size = rtlight->shadowmapatlassidesize;
4945 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4947 surfacesides = NULL;
4952 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4954 castermask = rtlight->static_shadowmap_casters;
4955 receivermask = rtlight->static_shadowmap_receivers;
4959 surfacesides = r_shadow_buffer_surfacesides;
4960 for (i = 0; i < numsurfaces; i++)
4962 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4963 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4964 castermask |= surfacesides[i];
4965 receivermask |= surfacesides[i];
4970 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
4971 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4972 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
4973 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4975 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4979 for (i = 0; i < numshadowentities; i++)
4980 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4981 for (i = 0; i < numshadowentities_noselfshadow; i++)
4982 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4985 // there is no need to render shadows for sides that have no receivers...
4986 castermask &= receivermask;
4988 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
4990 // render shadow casters into shadowmaps for this light
4991 for (side = 0; side < 6; side++)
4993 int bit = 1 << side;
4994 if (castermask & bit)
4996 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
4998 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4999 for (i = 0; i < numshadowentities; i++)
5000 if (entitysides[i] & bit)
5001 R_Shadow_DrawEntityShadow(shadowentities[i]);
5002 for (i = 0; i < numshadowentities_noselfshadow; i++)
5003 if (entitysides_noselfshadow[i] & bit)
5004 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5007 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
5008 if (numshadowentities_noselfshadow)
5010 for (side = 0; side < 6; side++)
5012 int bit = 1 << side;
5013 if (castermask & bit)
5015 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
5017 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
5018 for (i = 0; i < numshadowentities; i++)
5019 if (entitysides[i] & bit)
5020 R_Shadow_DrawEntityShadow(shadowentities[i]);
5026 static void R_Shadow_DrawLight(rtlight_t *rtlight)
5030 unsigned char *shadowtrispvs, *lighttrispvs;
5031 int numlightentities;
5032 int numlightentities_noselfshadow;
5033 int numshadowentities;
5034 int numshadowentities_noselfshadow;
5035 entity_render_t **lightentities;
5036 entity_render_t **lightentities_noselfshadow;
5037 entity_render_t **shadowentities;
5038 entity_render_t **shadowentities_noselfshadow;
5040 qboolean castshadows;
5042 // check if we cached this light this frame (meaning it is worth drawing)
5046 // set up a scissor rectangle for this light
5047 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
5050 // don't let sound skip if going slow
5051 if (r_refdef.scene.extraupdate)
5054 numlightentities = rtlight->cached_numlightentities;
5055 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
5056 numshadowentities = rtlight->cached_numshadowentities;
5057 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
5058 numsurfaces = rtlight->cached_numsurfaces;
5059 lightentities = rtlight->cached_lightentities;
5060 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
5061 shadowentities = rtlight->cached_shadowentities;
5062 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
5063 shadowtrispvs = rtlight->cached_shadowtrispvs;
5064 lighttrispvs = rtlight->cached_lighttrispvs;
5065 surfacelist = rtlight->cached_surfacelist;
5066 castshadows = rtlight->castshadows;
5068 // make this the active rtlight for rendering purposes
5069 R_Shadow_RenderMode_ActiveLight(rtlight);
5071 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
5073 // optionally draw visible shape of the shadow volumes
5074 // for performance analysis by level designers
5075 R_Shadow_RenderMode_VisibleShadowVolumes();
5077 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
5078 for (i = 0;i < numshadowentities;i++)
5079 R_Shadow_DrawEntityShadow(shadowentities[i]);
5080 for (i = 0;i < numshadowentities_noselfshadow;i++)
5081 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5082 R_Shadow_RenderMode_VisibleLighting(false, false);
5085 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
5087 // optionally draw the illuminated areas
5088 // for performance analysis by level designers
5089 R_Shadow_RenderMode_VisibleLighting(false, false);
5091 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5092 for (i = 0;i < numlightentities;i++)
5093 R_Shadow_DrawEntityLight(lightentities[i]);
5094 for (i = 0;i < numlightentities_noselfshadow;i++)
5095 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5098 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
5102 float shadowmapoffsetnoselfshadow = 0;
5103 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
5104 Matrix4x4_Abs(&radiustolight);
5106 size = rtlight->shadowmapatlassidesize;
5107 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
5109 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
5111 if (rtlight->cached_numshadowentities_noselfshadow)
5112 shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
5114 // render lighting using the depth texture as shadowmap
5115 // draw lighting in the unmasked areas
5116 if (numsurfaces + numlightentities)
5118 R_Shadow_RenderMode_Lighting(false, false, true, false);
5119 // draw lighting in the unmasked areas
5121 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5122 for (i = 0; i < numlightentities; i++)
5123 R_Shadow_DrawEntityLight(lightentities[i]);
5125 // offset to the noselfshadow part of the atlas and draw those too
5126 if (numlightentities_noselfshadow)
5128 R_Shadow_RenderMode_Lighting(false, false, true, true);
5129 for (i = 0; i < numlightentities_noselfshadow; i++)
5130 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5133 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5134 if (r_shadow_usingdeferredprepass)
5135 R_Shadow_RenderMode_DrawDeferredLight(true);
5137 else if (castshadows && vid.stencil)
5139 // draw stencil shadow volumes to mask off pixels that are in shadow
5140 // so that they won't receive lighting
5141 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
5142 R_Shadow_ClearStencil();
5145 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
5146 for (i = 0;i < numshadowentities;i++)
5147 R_Shadow_DrawEntityShadow(shadowentities[i]);
5149 // draw lighting in the unmasked areas
5150 R_Shadow_RenderMode_Lighting(true, false, false, false);
5151 for (i = 0;i < numlightentities_noselfshadow;i++)
5152 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5154 for (i = 0;i < numshadowentities_noselfshadow;i++)
5155 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5157 // draw lighting in the unmasked areas
5158 R_Shadow_RenderMode_Lighting(true, false, false, false);
5160 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5161 for (i = 0;i < numlightentities;i++)
5162 R_Shadow_DrawEntityLight(lightentities[i]);
5164 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5165 if (r_shadow_usingdeferredprepass)
5166 R_Shadow_RenderMode_DrawDeferredLight(false);
5170 // draw lighting in the unmasked areas
5171 R_Shadow_RenderMode_Lighting(false, false, false, false);
5173 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5174 for (i = 0;i < numlightentities;i++)
5175 R_Shadow_DrawEntityLight(lightentities[i]);
5176 for (i = 0;i < numlightentities_noselfshadow;i++)
5177 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5179 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5180 if (r_shadow_usingdeferredprepass)
5181 R_Shadow_RenderMode_DrawDeferredLight(false);
5185 static void R_Shadow_FreeDeferred(void)
5187 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
5188 r_shadow_prepassgeometryfbo = 0;
5190 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
5191 r_shadow_prepasslightingdiffusespecularfbo = 0;
5193 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
5194 r_shadow_prepasslightingdiffusefbo = 0;
5196 if (r_shadow_prepassgeometrydepthbuffer)
5197 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
5198 r_shadow_prepassgeometrydepthbuffer = NULL;
5200 if (r_shadow_prepassgeometrynormalmaptexture)
5201 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
5202 r_shadow_prepassgeometrynormalmaptexture = NULL;
5204 if (r_shadow_prepasslightingdiffusetexture)
5205 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
5206 r_shadow_prepasslightingdiffusetexture = NULL;
5208 if (r_shadow_prepasslightingspeculartexture)
5209 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
5210 r_shadow_prepasslightingspeculartexture = NULL;
5213 void R_Shadow_DrawPrepass(void)
5217 entity_render_t *ent;
5218 float clearcolor[4];
5220 R_Mesh_ResetTextureState();
5222 GL_ColorMask(1,1,1,1);
5223 GL_BlendFunc(GL_ONE, GL_ZERO);
5226 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5227 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
5228 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
5229 if (r_timereport_active)
5230 R_TimeReport("prepasscleargeom");
5232 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
5233 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
5234 if (r_timereport_active)
5235 R_TimeReport("prepassworld");
5237 for (i = 0;i < r_refdef.scene.numentities;i++)
5239 if (!r_refdef.viewcache.entityvisible[i])
5241 ent = r_refdef.scene.entities[i];
5242 if (ent->model && ent->model->DrawPrepass != NULL)
5243 ent->model->DrawPrepass(ent);
5246 if (r_timereport_active)
5247 R_TimeReport("prepassmodels");
5249 GL_DepthMask(false);
5250 GL_ColorMask(1,1,1,1);
5253 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5254 Vector4Set(clearcolor, 0, 0, 0, 0);
5255 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
5256 if (r_timereport_active)
5257 R_TimeReport("prepassclearlit");
5259 R_Shadow_RenderMode_Begin();
5261 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5262 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5264 R_Shadow_RenderMode_End();
5266 if (r_timereport_active)
5267 R_TimeReport("prepasslights");
5270 #define MAX_SCENELIGHTS 65536
5271 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
5273 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
5275 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
5277 r_shadow_scenemaxlights *= 2;
5278 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
5279 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
5281 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
5285 void R_Shadow_DrawLightSprites(void);
5286 void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
5295 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
5296 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
5297 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
5299 if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
5300 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
5301 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
5302 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
5303 r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) ||
5304 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
5305 r_shadow_shadowmapborder != shadowmapborder ||
5306 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
5307 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
5308 R_Shadow_FreeShadowMaps();
5310 r_shadow_fb_fbo = fbo;
5311 r_shadow_fb_depthtexture = depthtexture;
5312 r_shadow_fb_colortexture = colortexture;
5314 r_shadow_usingshadowmaportho = false;
5316 switch (vid.renderpath)
5318 case RENDERPATH_GL20:
5319 case RENDERPATH_D3D9:
5320 case RENDERPATH_D3D10:
5321 case RENDERPATH_D3D11:
5322 case RENDERPATH_SOFT:
5324 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
5326 r_shadow_usingdeferredprepass = false;
5327 if (r_shadow_prepass_width)
5328 R_Shadow_FreeDeferred();
5329 r_shadow_prepass_width = r_shadow_prepass_height = 0;
5333 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
5335 R_Shadow_FreeDeferred();
5337 r_shadow_usingdeferredprepass = true;
5338 r_shadow_prepass_width = vid.width;
5339 r_shadow_prepass_height = vid.height;
5340 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
5341 r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER32F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
5342 r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER16F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
5343 r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER16F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
5345 // set up the geometry pass fbo (depth + normalmap)
5346 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5347 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5348 // render depth into a renderbuffer and other important properties into the normalmap texture
5350 // set up the lighting pass fbo (diffuse + specular)
5351 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5352 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5353 // render diffuse into one texture and specular into another,
5354 // with depth and normalmap bound as textures,
5355 // with depth bound as attachment as well
5357 // set up the lighting pass fbo (diffuse)
5358 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5359 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5360 // render diffuse into one texture,
5361 // with depth and normalmap bound as textures,
5362 // with depth bound as attachment as well
5366 case RENDERPATH_GL11:
5367 case RENDERPATH_GL13:
5368 case RENDERPATH_GLES1:
5369 case RENDERPATH_GLES2:
5370 r_shadow_usingdeferredprepass = false;
5374 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);
5376 r_shadow_scenenumlights = 0;
5377 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5378 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5379 for (lightindex = 0; lightindex < range; lightindex++)
5381 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5382 if (light && (light->flags & flag))
5384 R_Shadow_PrepareLight(&light->rtlight);
5385 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5388 if (r_refdef.scene.rtdlight)
5390 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5392 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
5393 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
5396 else if (gl_flashblend.integer)
5398 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5400 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
5401 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
5402 VectorScale(rtlight->color, f, rtlight->currentcolor);
5406 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
5407 if (r_shadow_debuglight.integer >= 0)
5409 r_shadow_scenenumlights = 0;
5410 lightindex = r_shadow_debuglight.integer;
5411 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5414 R_Shadow_PrepareLight(&light->rtlight);
5415 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5419 // if we're doing shadowmaps we need to prepare the atlas layout now
5420 if (R_Shadow_ShadowMappingEnabled())
5424 // allocate shadowmaps in the atlas now
5425 // we may have to make multiple attempts to fit the shadowmaps in the limited space of the atlas, this will appear as lod popping of all shadowmaps whenever it changes, but at least we can still cast shadows from all lights...
5426 for (lod = 0; lod < 16; lod++)
5428 int packing_success = 0;
5429 int packing_failure = 0;
5430 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
5431 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
5432 if (r_shadow_shadowmapatlas_modelshadows_size)
5433 Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, r_shadow_shadowmapatlas_modelshadows_size, r_shadow_shadowmapatlas_modelshadows_size, &r_shadow_shadowmapatlas_modelshadows_x, &r_shadow_shadowmapatlas_modelshadows_y);
5434 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5436 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
5437 int size = rtlight->shadowmapsidesize >> lod;
5439 if (!rtlight->castshadows)
5441 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
5444 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
5445 if (rtlight->cached_numshadowentities_noselfshadow)
5447 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
5449 rtlight->shadowmapatlassidesize = size;
5454 // note down that we failed to pack this one, it will have to disable shadows
5455 rtlight->shadowmapatlassidesize = 0;
5459 // generally everything fits and we stop here on the first iteration
5460 if (packing_failure == 0)
5465 if (r_editlights.integer)
5466 R_Shadow_DrawLightSprites();
5469 void R_Shadow_DrawShadowMaps(void)
5471 R_Shadow_RenderMode_Begin();
5472 R_Shadow_RenderMode_ActiveLight(NULL);
5474 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
5475 R_Shadow_ClearShadowMapTexture();
5477 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
5478 if (r_shadow_shadowmapatlas_modelshadows_size)
5480 R_Shadow_DrawModelShadowMaps();
5481 // don't let sound skip if going slow
5482 if (r_refdef.scene.extraupdate)
5486 if (R_Shadow_ShadowMappingEnabled())
5489 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5490 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
5493 R_Shadow_RenderMode_End();
5496 void R_Shadow_DrawLights(void)
5500 R_Shadow_RenderMode_Begin();
5502 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5503 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5505 R_Shadow_RenderMode_End();
5508 #define MAX_MODELSHADOWS 1024
5509 static int r_shadow_nummodelshadows;
5510 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
5512 void R_Shadow_PrepareModelShadows(void)
5515 float scale, size, radius, dot1, dot2;
5516 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5517 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
5518 entity_render_t *ent;
5520 r_shadow_nummodelshadows = 0;
5521 r_shadow_shadowmapatlas_modelshadows_size = 0;
5523 if (!r_refdef.scene.numentities || r_refdef.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
5526 switch (r_shadow_shadowmode)
5528 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
5529 if (r_shadows.integer >= 2)
5532 case R_SHADOW_SHADOWMODE_STENCIL:
5535 for (i = 0; i < r_refdef.scene.numentities; i++)
5537 ent = r_refdef.scene.entities[i];
5538 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5540 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5542 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5543 R_AnimCache_GetEntity(ent, false, false);
5551 size = 2 * r_shadow_shadowmapmaxsize;
5552 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
5553 radius = 0.5f * size / scale;
5555 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5556 VectorCopy(prvmshadowdir, shadowdir);
5557 VectorNormalize(shadowdir);
5558 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5559 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5560 if (fabs(dot1) <= fabs(dot2))
5561 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5563 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5564 VectorNormalize(shadowforward);
5565 CrossProduct(shadowdir, shadowforward, shadowright);
5566 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5567 VectorCopy(prvmshadowfocus, shadowfocus);
5568 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5569 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5570 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5571 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5572 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5574 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5576 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5577 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5578 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5579 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5580 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5581 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5583 for (i = 0; i < r_refdef.scene.numentities; i++)
5585 ent = r_refdef.scene.entities[i];
5586 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
5588 // cast shadows from anything of the map (submodels are optional)
5589 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5591 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5593 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5594 R_AnimCache_GetEntity(ent, false, false);
5598 if (r_shadow_nummodelshadows)
5600 r_shadow_shadowmapatlas_modelshadows_x = 0;
5601 r_shadow_shadowmapatlas_modelshadows_y = 0;
5602 r_shadow_shadowmapatlas_modelshadows_size = size;
5606 static void R_Shadow_DrawModelShadowMaps(void)
5609 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
5610 entity_render_t *ent;
5611 vec3_t relativelightorigin;
5612 vec3_t relativelightdirection, relativeforward, relativeright;
5613 vec3_t relativeshadowmins, relativeshadowmaxs;
5614 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
5615 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5617 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
5618 r_viewport_t viewport;
5620 size = r_shadow_shadowmapatlas_modelshadows_size;
5621 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
5622 radius = 0.5f / scale;
5623 nearclip = -r_shadows_throwdistance.value;
5624 farclip = r_shadows_throwdistance.value;
5625 bias = (r_shadows_shadowmapbias.value < 0) ? r_shadow_shadowmapping_bias.value : r_shadows_shadowmapbias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
5627 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
5628 r_shadow_modelshadowmap_parameters[0] = size;
5629 r_shadow_modelshadowmap_parameters[1] = size;
5630 r_shadow_modelshadowmap_parameters[2] = 1.0;
5631 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
5632 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
5633 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
5634 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
5635 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
5636 r_shadow_usingshadowmaportho = true;
5638 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5639 VectorCopy(prvmshadowdir, shadowdir);
5640 VectorNormalize(shadowdir);
5641 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5642 VectorCopy(prvmshadowfocus, shadowfocus);
5643 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5644 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5645 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5646 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5647 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5648 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5649 if (fabs(dot1) <= fabs(dot2))
5650 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5652 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5653 VectorNormalize(shadowforward);
5654 VectorM(scale, shadowforward, &m[0]);
5655 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5657 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
5658 CrossProduct(shadowdir, shadowforward, shadowright);
5659 VectorM(scale, shadowright, &m[4]);
5660 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
5661 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
5662 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
5663 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
5664 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
5665 R_Viewport_InitOrtho(&viewport, &cameramatrix, r_shadow_shadowmapatlas_modelshadows_x, r_shadow_shadowmapatlas_modelshadows_y, r_shadow_shadowmapatlas_modelshadows_size, r_shadow_shadowmapatlas_modelshadows_size, 0, 0, 1, 1, 0, -1, NULL);
5666 R_SetViewport(&viewport);
5668 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5670 // render into a slightly restricted region so that the borders of the
5671 // shadowmap area fade away, rather than streaking across everything
5672 // outside the usable area
5673 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
5675 for (i = 0;i < r_shadow_nummodelshadows;i++)
5677 ent = r_shadow_modelshadows[i];
5678 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5679 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
5680 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5681 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
5682 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
5683 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5684 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5685 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5686 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5687 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5688 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5689 RSurf_ActiveModelEntity(ent, false, false, false);
5690 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
5691 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5697 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
5699 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
5701 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
5702 Cvar_SetValueQuick(&r_test, 0);
5707 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
5708 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
5709 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
5710 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
5711 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
5712 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
5714 switch (vid.renderpath)
5716 case RENDERPATH_GL11:
5717 case RENDERPATH_GL13:
5718 case RENDERPATH_GL20:
5719 case RENDERPATH_SOFT:
5720 case RENDERPATH_GLES1:
5721 case RENDERPATH_GLES2:
5723 case RENDERPATH_D3D9:
5724 case RENDERPATH_D3D10:
5725 case RENDERPATH_D3D11:
5726 #ifdef MATRIX4x4_OPENGLORIENTATION
5727 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5728 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
5729 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
5730 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
5732 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5733 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
5734 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
5735 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
5741 void R_Shadow_DrawModelShadows(void)
5744 float relativethrowdistance;
5745 entity_render_t *ent;
5746 vec3_t relativelightorigin;
5747 vec3_t relativelightdirection;
5748 vec3_t relativeshadowmins, relativeshadowmaxs;
5749 vec3_t tmp, shadowdir;
5750 prvm_vec3_t prvmshadowdir;
5752 if (!r_shadow_nummodelshadows || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
5755 R_ResetViewRendering3D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5756 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
5757 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5758 R_Shadow_RenderMode_Begin();
5759 R_Shadow_RenderMode_ActiveLight(NULL);
5760 r_shadow_lightscissor[0] = r_refdef.view.x;
5761 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
5762 r_shadow_lightscissor[2] = r_refdef.view.width;
5763 r_shadow_lightscissor[3] = r_refdef.view.height;
5764 R_Shadow_RenderMode_StencilShadowVolumes(false);
5767 if (r_shadows.integer == 2)
5769 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5770 VectorCopy(prvmshadowdir, shadowdir);
5771 VectorNormalize(shadowdir);
5774 R_Shadow_ClearStencil();
5776 for (i = 0;i < r_shadow_nummodelshadows;i++)
5778 ent = r_shadow_modelshadows[i];
5780 // cast shadows from anything of the map (submodels are optional)
5781 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5782 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
5783 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
5784 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
5785 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5788 if(ent->entitynumber != 0)
5790 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
5792 // FIXME handle this
5793 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5797 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
5798 int entnum, entnum2, recursion;
5799 entnum = entnum2 = ent->entitynumber;
5800 for(recursion = 32; recursion > 0; --recursion)
5802 entnum2 = cl.entities[entnum].state_current.tagentity;
5803 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
5808 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
5810 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
5811 // transform into modelspace of OUR entity
5812 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
5813 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
5816 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5820 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5823 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
5824 RSurf_ActiveModelEntity(ent, false, false, false);
5825 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
5826 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5829 // not really the right mode, but this will disable any silly stencil features
5830 R_Shadow_RenderMode_End();
5832 // set up ortho view for rendering this pass
5833 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5834 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5835 //GL_ScissorTest(true);
5836 //R_EntityMatrix(&identitymatrix);
5837 //R_Mesh_ResetTextureState();
5838 R_ResetViewRendering2D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5840 // set up a darkening blend on shadowed areas
5841 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5842 //GL_DepthRange(0, 1);
5843 //GL_DepthTest(false);
5844 //GL_DepthMask(false);
5845 //GL_PolygonOffset(0, 0);CHECKGLERROR
5846 GL_Color(0, 0, 0, r_shadows_darken.value);
5847 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5848 //GL_DepthFunc(GL_ALWAYS);
5849 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5851 // apply the blend to the shadowed areas
5852 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5853 R_SetupShader_Generic_NoTexture(false, true);
5854 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5856 // restore the viewport
5857 R_SetViewport(&r_refdef.view.viewport);
5859 // restore other state to normal
5860 //R_Shadow_RenderMode_End();
5863 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5866 vec3_t centerorigin;
5867 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5870 // if it's too close, skip it
5871 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5873 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5876 if (usequery && r_numqueries + 2 <= r_maxqueries)
5878 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5879 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5880 // 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
5881 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5883 switch(vid.renderpath)
5885 case RENDERPATH_GL11:
5886 case RENDERPATH_GL13:
5887 case RENDERPATH_GL20:
5888 case RENDERPATH_GLES1:
5889 case RENDERPATH_GLES2:
5890 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5892 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5893 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5894 GL_DepthFunc(GL_ALWAYS);
5895 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5896 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5897 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5898 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5899 GL_DepthFunc(GL_LEQUAL);
5900 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5901 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5902 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5903 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5904 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5908 case RENDERPATH_D3D9:
5909 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5911 case RENDERPATH_D3D10:
5912 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5914 case RENDERPATH_D3D11:
5915 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5917 case RENDERPATH_SOFT:
5918 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5922 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5925 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5927 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5930 unsigned int occlude = 0;
5931 GLint allpixels = 0, visiblepixels = 0;
5933 // now we have to check the query result
5934 if (rtlight->corona_queryindex_visiblepixels)
5936 switch(vid.renderpath)
5938 case RENDERPATH_GL11:
5939 case RENDERPATH_GL13:
5940 case RENDERPATH_GL20:
5941 case RENDERPATH_GLES1:
5942 case RENDERPATH_GLES2:
5943 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5945 // See if we can use the GPU-side method to prevent implicit sync
5946 if (vid.support.arb_query_buffer_object) {
5947 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
5948 if (!r_shadow_occlusion_buf) {
5949 qglGenBuffersARB(1, &r_shadow_occlusion_buf);
5950 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5951 qglBufferDataARB(GL_QUERY_BUFFER_ARB, 8, NULL, GL_DYNAMIC_COPY);
5953 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5955 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(0));
5956 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4));
5957 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
5958 occlude = MATERIALFLAG_OCCLUDE;
5960 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5961 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5962 if (visiblepixels < 1 || allpixels < 1)
5964 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5966 cscale *= rtlight->corona_visibility;
5972 case RENDERPATH_D3D9:
5973 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5975 case RENDERPATH_D3D10:
5976 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5978 case RENDERPATH_D3D11:
5979 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5981 case RENDERPATH_SOFT:
5982 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5990 // FIXME: these traces should scan all render entities instead of cl.world
5991 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
5994 VectorScale(rtlight->currentcolor, cscale, color);
5995 if (VectorLength(color) > (1.0f / 256.0f))
5998 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
6001 VectorNegate(color, color);
6002 GL_BlendEquationSubtract(true);
6004 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
6005 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);
6006 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
6008 GL_BlendEquationSubtract(false);
6012 void R_Shadow_DrawCoronas(void)
6015 qboolean usequery = false;
6020 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
6022 if (r_fb.water.renderingscene)
6024 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6025 R_EntityMatrix(&identitymatrix);
6027 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6029 // check occlusion of coronas
6030 // use GL_ARB_occlusion_query if available
6031 // otherwise use raytraces
6033 switch (vid.renderpath)
6035 case RENDERPATH_GL11:
6036 case RENDERPATH_GL13:
6037 case RENDERPATH_GL20:
6038 case RENDERPATH_GLES1:
6039 case RENDERPATH_GLES2:
6040 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
6041 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
6044 GL_ColorMask(0,0,0,0);
6045 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
6046 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
6049 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
6050 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
6052 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
6055 RSurf_ActiveWorldEntity();
6056 GL_BlendFunc(GL_ONE, GL_ZERO);
6057 GL_CullFace(GL_NONE);
6058 GL_DepthMask(false);
6059 GL_DepthRange(0, 1);
6060 GL_PolygonOffset(0, 0);
6062 R_Mesh_ResetTextureState();
6063 R_SetupShader_Generic_NoTexture(false, false);
6067 case RENDERPATH_D3D9:
6069 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6071 case RENDERPATH_D3D10:
6072 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6074 case RENDERPATH_D3D11:
6075 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6077 case RENDERPATH_SOFT:
6079 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6082 for (lightindex = 0;lightindex < range;lightindex++)
6084 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6087 rtlight = &light->rtlight;
6088 rtlight->corona_visibility = 0;
6089 rtlight->corona_queryindex_visiblepixels = 0;
6090 rtlight->corona_queryindex_allpixels = 0;
6091 if (!(rtlight->flags & flag))
6093 if (rtlight->corona <= 0)
6095 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
6097 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6099 for (i = 0;i < r_refdef.scene.numlights;i++)
6101 rtlight = r_refdef.scene.lights[i];
6102 rtlight->corona_visibility = 0;
6103 rtlight->corona_queryindex_visiblepixels = 0;
6104 rtlight->corona_queryindex_allpixels = 0;
6105 if (!(rtlight->flags & flag))
6107 if (rtlight->corona <= 0)
6109 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6112 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
6114 // now draw the coronas using the query data for intensity info
6115 for (lightindex = 0;lightindex < range;lightindex++)
6117 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6120 rtlight = &light->rtlight;
6121 if (rtlight->corona_visibility <= 0)
6123 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6125 for (i = 0;i < r_refdef.scene.numlights;i++)
6127 rtlight = r_refdef.scene.lights[i];
6128 if (rtlight->corona_visibility <= 0)
6130 if (gl_flashblend.integer)
6131 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
6133 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6139 static dlight_t *R_Shadow_NewWorldLight(void)
6141 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
6144 static void R_Shadow_UpdateWorldLight(dlight_t *light, vec3_t origin, vec3_t angles, vec3_t color, vec_t radius, vec_t corona, int style, int shadowenable, const char *cubemapname, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
6148 // note that style is no longer validated here, -1 is used for unstyled lights and >= MAX_LIGHTSTYLES is accepted for sake of editing rtlights files that might be out of bounds but perfectly formatted
6150 // validate parameters
6154 // copy to light properties
6155 VectorCopy(origin, light->origin);
6156 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
6157 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
6158 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
6160 light->color[0] = max(color[0], 0);
6161 light->color[1] = max(color[1], 0);
6162 light->color[2] = max(color[2], 0);
6164 light->color[0] = color[0];
6165 light->color[1] = color[1];
6166 light->color[2] = color[2];
6167 light->radius = max(radius, 0);
6168 light->style = style;
6169 light->shadow = shadowenable;
6170 light->corona = corona;
6171 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
6172 light->coronasizescale = coronasizescale;
6173 light->ambientscale = ambientscale;
6174 light->diffusescale = diffusescale;
6175 light->specularscale = specularscale;
6176 light->flags = flags;
6178 // update renderable light data
6179 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
6180 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);
6183 static void R_Shadow_FreeWorldLight(dlight_t *light)
6185 if (r_shadow_selectedlight == light)
6186 r_shadow_selectedlight = NULL;
6187 R_RTLight_Uncompile(&light->rtlight);
6188 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
6191 void R_Shadow_ClearWorldLights(void)
6195 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6196 for (lightindex = 0;lightindex < range;lightindex++)
6198 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6200 R_Shadow_FreeWorldLight(light);
6202 r_shadow_selectedlight = NULL;
6205 static void R_Shadow_SelectLight(dlight_t *light)
6207 if (r_shadow_selectedlight)
6208 r_shadow_selectedlight->selected = false;
6209 r_shadow_selectedlight = light;
6210 if (r_shadow_selectedlight)
6211 r_shadow_selectedlight->selected = true;
6214 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6216 // this is never batched (there can be only one)
6218 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
6219 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6220 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6223 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6228 skinframe_t *skinframe;
6231 // this is never batched (due to the ent parameter changing every time)
6232 // so numsurfaces == 1 and surfacelist[0] == lightnumber
6233 const dlight_t *light = (dlight_t *)ent;
6236 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
6239 VectorScale(light->color, intensity, spritecolor);
6240 if (VectorLength(spritecolor) < 0.1732f)
6241 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
6242 if (VectorLength(spritecolor) > 1.0f)
6243 VectorNormalize(spritecolor);
6245 // draw light sprite
6246 if (light->cubemapname[0] && !light->shadow)
6247 skinframe = r_editlights_sprcubemapnoshadowlight;
6248 else if (light->cubemapname[0])
6249 skinframe = r_editlights_sprcubemaplight;
6250 else if (!light->shadow)
6251 skinframe = r_editlights_sprnoshadowlight;
6253 skinframe = r_editlights_sprlight;
6255 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);
6256 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6258 // draw selection sprite if light is selected
6259 if (light->selected)
6261 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6262 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6263 // VorteX todo: add normalmode/realtime mode light overlay sprites?
6267 void R_Shadow_DrawLightSprites(void)
6271 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6272 for (lightindex = 0;lightindex < range;lightindex++)
6274 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6276 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
6278 if (!r_editlights_lockcursor)
6279 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
6282 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
6287 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6288 if (lightindex >= range)
6290 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6293 rtlight = &light->rtlight;
6294 //if (!(rtlight->flags & flag))
6296 VectorCopy(rtlight->shadoworigin, origin);
6297 *radius = rtlight->radius;
6298 VectorCopy(rtlight->color, color);
6302 static void R_Shadow_SelectLightInView(void)
6304 float bestrating, rating, temp[3];
6308 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6312 if (r_editlights_lockcursor)
6314 for (lightindex = 0;lightindex < range;lightindex++)
6316 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6319 VectorSubtract(light->origin, r_refdef.view.origin, temp);
6320 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
6323 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
6324 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1.0f)
6326 bestrating = rating;
6331 R_Shadow_SelectLight(best);
6334 void R_Shadow_LoadWorldLights(void)
6336 int n, a, style, shadow, flags;
6337 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
6338 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
6339 if (cl.worldmodel == NULL)
6341 Con_Print("No map loaded.\n");
6344 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6345 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6355 for (;COM_Parse(t, true) && strcmp(
6356 if (COM_Parse(t, true))
6358 if (com_token[0] == '!')
6361 origin[0] = atof(com_token+1);
6364 origin[0] = atof(com_token);
6369 while (*s && *s != '\n' && *s != '\r')
6375 // check for modifier flags
6382 #if _MSC_VER >= 1400
6383 #define sscanf sscanf_s
6385 cubemapname[sizeof(cubemapname)-1] = 0;
6386 #if MAX_QPATH != 128
6387 #error update this code if MAX_QPATH changes
6389 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
6390 #if _MSC_VER >= 1400
6391 , sizeof(cubemapname)
6393 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
6396 flags = LIGHTFLAG_REALTIMEMODE;
6404 coronasizescale = 0.25f;
6406 VectorClear(angles);
6409 if (a < 9 || !strcmp(cubemapname, "\"\""))
6411 // remove quotes on cubemapname
6412 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
6415 namelen = strlen(cubemapname) - 2;
6416 memmove(cubemapname, cubemapname + 1, namelen);
6417 cubemapname[namelen] = '\0';
6421 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);
6424 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6432 Con_Printf("invalid rtlights file \"%s\"\n", name);
6433 Mem_Free(lightsstring);
6437 void R_Shadow_SaveWorldLights(void)
6441 size_t bufchars, bufmaxchars;
6443 char name[MAX_QPATH];
6444 char line[MAX_INPUTLINE];
6445 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
6446 // I hate lines which are 3 times my screen size :( --blub
6449 if (cl.worldmodel == NULL)
6451 Con_Print("No map loaded.\n");
6454 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6455 bufchars = bufmaxchars = 0;
6457 for (lightindex = 0;lightindex < range;lightindex++)
6459 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6462 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
6463 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);
6464 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
6465 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]);
6467 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);
6468 if (bufchars + strlen(line) > bufmaxchars)
6470 bufmaxchars = bufchars + strlen(line) + 2048;
6472 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
6476 memcpy(buf, oldbuf, bufchars);
6482 memcpy(buf + bufchars, line, strlen(line));
6483 bufchars += strlen(line);
6487 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
6492 void R_Shadow_LoadLightsFile(void)
6495 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
6496 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
6497 if (cl.worldmodel == NULL)
6499 Con_Print("No map loaded.\n");
6502 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
6503 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6511 while (*s && *s != '\n' && *s != '\r')
6517 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);
6521 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);
6524 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
6525 radius = bound(15, radius, 4096);
6526 VectorScale(color, (2.0f / (8388608.0f)), color);
6527 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6535 Con_Printf("invalid lights file \"%s\"\n", name);
6536 Mem_Free(lightsstring);
6540 // tyrlite/hmap2 light types in the delay field
6541 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
6543 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
6555 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
6556 char key[256], value[MAX_INPUTLINE];
6559 if (cl.worldmodel == NULL)
6561 Con_Print("No map loaded.\n");
6564 // try to load a .ent file first
6565 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
6566 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
6567 // and if that is not found, fall back to the bsp file entity string
6569 data = cl.worldmodel->brush.entities;
6572 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
6574 type = LIGHTTYPE_MINUSX;
6575 origin[0] = origin[1] = origin[2] = 0;
6576 originhack[0] = originhack[1] = originhack[2] = 0;
6577 angles[0] = angles[1] = angles[2] = 0;
6578 color[0] = color[1] = color[2] = 1;
6579 light[0] = light[1] = light[2] = 1;light[3] = 300;
6580 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
6590 if (!COM_ParseToken_Simple(&data, false, false, true))
6592 if (com_token[0] == '}')
6593 break; // end of entity
6594 if (com_token[0] == '_')
6595 strlcpy(key, com_token + 1, sizeof(key));
6597 strlcpy(key, com_token, sizeof(key));
6598 while (key[strlen(key)-1] == ' ') // remove trailing spaces
6599 key[strlen(key)-1] = 0;
6600 if (!COM_ParseToken_Simple(&data, false, false, true))
6602 strlcpy(value, com_token, sizeof(value));
6604 // now that we have the key pair worked out...
6605 if (!strcmp("light", key))
6607 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
6611 light[0] = vec[0] * (1.0f / 256.0f);
6612 light[1] = vec[0] * (1.0f / 256.0f);
6613 light[2] = vec[0] * (1.0f / 256.0f);
6619 light[0] = vec[0] * (1.0f / 255.0f);
6620 light[1] = vec[1] * (1.0f / 255.0f);
6621 light[2] = vec[2] * (1.0f / 255.0f);
6625 else if (!strcmp("delay", key))
6627 else if (!strcmp("origin", key))
6628 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
6629 else if (!strcmp("angle", key))
6630 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
6631 else if (!strcmp("angles", key))
6632 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
6633 else if (!strcmp("color", key))
6634 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
6635 else if (!strcmp("wait", key))
6636 fadescale = atof(value);
6637 else if (!strcmp("classname", key))
6639 if (!strncmp(value, "light", 5))
6642 if (!strcmp(value, "light_fluoro"))
6647 overridecolor[0] = 1;
6648 overridecolor[1] = 1;
6649 overridecolor[2] = 1;
6651 if (!strcmp(value, "light_fluorospark"))
6656 overridecolor[0] = 1;
6657 overridecolor[1] = 1;
6658 overridecolor[2] = 1;
6660 if (!strcmp(value, "light_globe"))
6665 overridecolor[0] = 1;
6666 overridecolor[1] = 0.8;
6667 overridecolor[2] = 0.4;
6669 if (!strcmp(value, "light_flame_large_yellow"))
6674 overridecolor[0] = 1;
6675 overridecolor[1] = 0.5;
6676 overridecolor[2] = 0.1;
6678 if (!strcmp(value, "light_flame_small_yellow"))
6683 overridecolor[0] = 1;
6684 overridecolor[1] = 0.5;
6685 overridecolor[2] = 0.1;
6687 if (!strcmp(value, "light_torch_small_white"))
6692 overridecolor[0] = 1;
6693 overridecolor[1] = 0.5;
6694 overridecolor[2] = 0.1;
6696 if (!strcmp(value, "light_torch_small_walltorch"))
6701 overridecolor[0] = 1;
6702 overridecolor[1] = 0.5;
6703 overridecolor[2] = 0.1;
6707 else if (!strcmp("style", key))
6708 style = atoi(value);
6709 else if (!strcmp("skin", key))
6710 skin = (int)atof(value);
6711 else if (!strcmp("pflags", key))
6712 pflags = (int)atof(value);
6713 //else if (!strcmp("effects", key))
6714 // effects = (int)atof(value);
6715 else if (cl.worldmodel->type == mod_brushq3)
6717 if (!strcmp("scale", key))
6718 lightscale = atof(value);
6719 if (!strcmp("fade", key))
6720 fadescale = atof(value);
6725 if (lightscale <= 0)
6729 if (color[0] == color[1] && color[0] == color[2])
6731 color[0] *= overridecolor[0];
6732 color[1] *= overridecolor[1];
6733 color[2] *= overridecolor[2];
6735 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
6736 color[0] = color[0] * light[0];
6737 color[1] = color[1] * light[1];
6738 color[2] = color[2] * light[2];
6741 case LIGHTTYPE_MINUSX:
6743 case LIGHTTYPE_RECIPX:
6745 VectorScale(color, (1.0f / 16.0f), color);
6747 case LIGHTTYPE_RECIPXX:
6749 VectorScale(color, (1.0f / 16.0f), color);
6752 case LIGHTTYPE_NONE:
6756 case LIGHTTYPE_MINUSXX:
6759 VectorAdd(origin, originhack, origin);
6761 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va(vabuf, sizeof(vabuf), "cubemaps/%i", skin) : NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6764 Mem_Free(entfiledata);
6768 static void R_Shadow_SetCursorLocationForView(void)
6771 vec3_t dest, endpos;
6773 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
6774 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true);
6775 if (trace.fraction < 1)
6777 dist = trace.fraction * r_editlights_cursordistance.value;
6778 push = r_editlights_cursorpushback.value;
6782 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
6783 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
6787 VectorClear( endpos );
6789 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6790 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6791 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6794 void R_Shadow_UpdateWorldLightSelection(void)
6796 if (r_editlights.integer)
6798 R_Shadow_SetCursorLocationForView();
6799 R_Shadow_SelectLightInView();
6802 R_Shadow_SelectLight(NULL);
6805 static void R_Shadow_EditLights_Clear_f(void)
6807 R_Shadow_ClearWorldLights();
6810 void R_Shadow_EditLights_Reload_f(void)
6814 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
6815 R_Shadow_ClearWorldLights();
6816 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
6818 R_Shadow_LoadWorldLights();
6819 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6820 R_Shadow_LoadLightsFile();
6822 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
6824 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6825 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6829 static void R_Shadow_EditLights_Save_f(void)
6833 R_Shadow_SaveWorldLights();
6836 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6838 R_Shadow_ClearWorldLights();
6839 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6842 static void R_Shadow_EditLights_ImportLightsFile_f(void)
6844 R_Shadow_ClearWorldLights();
6845 R_Shadow_LoadLightsFile();
6848 static void R_Shadow_EditLights_Spawn_f(void)
6851 if (!r_editlights.integer)
6853 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6856 if (Cmd_Argc() != 1)
6858 Con_Print("r_editlights_spawn does not take parameters\n");
6861 color[0] = color[1] = color[2] = 1;
6862 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6865 static void R_Shadow_EditLights_Edit_f(void)
6867 vec3_t origin, angles, color;
6868 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6869 int style, shadows, flags, normalmode, realtimemode;
6870 char cubemapname[MAX_INPUTLINE];
6871 if (!r_editlights.integer)
6873 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6876 if (!r_shadow_selectedlight)
6878 Con_Print("No selected light.\n");
6881 VectorCopy(r_shadow_selectedlight->origin, origin);
6882 VectorCopy(r_shadow_selectedlight->angles, angles);
6883 VectorCopy(r_shadow_selectedlight->color, color);
6884 radius = r_shadow_selectedlight->radius;
6885 style = r_shadow_selectedlight->style;
6886 if (r_shadow_selectedlight->cubemapname)
6887 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6890 shadows = r_shadow_selectedlight->shadow;
6891 corona = r_shadow_selectedlight->corona;
6892 coronasizescale = r_shadow_selectedlight->coronasizescale;
6893 ambientscale = r_shadow_selectedlight->ambientscale;
6894 diffusescale = r_shadow_selectedlight->diffusescale;
6895 specularscale = r_shadow_selectedlight->specularscale;
6896 flags = r_shadow_selectedlight->flags;
6897 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6898 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6899 if (!strcmp(Cmd_Argv(1), "origin"))
6901 if (Cmd_Argc() != 5)
6903 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6906 origin[0] = atof(Cmd_Argv(2));
6907 origin[1] = atof(Cmd_Argv(3));
6908 origin[2] = atof(Cmd_Argv(4));
6910 else if (!strcmp(Cmd_Argv(1), "originscale"))
6912 if (Cmd_Argc() != 5)
6914 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6917 origin[0] *= atof(Cmd_Argv(2));
6918 origin[1] *= atof(Cmd_Argv(3));
6919 origin[2] *= atof(Cmd_Argv(4));
6921 else if (!strcmp(Cmd_Argv(1), "originx"))
6923 if (Cmd_Argc() != 3)
6925 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6928 origin[0] = atof(Cmd_Argv(2));
6930 else if (!strcmp(Cmd_Argv(1), "originy"))
6932 if (Cmd_Argc() != 3)
6934 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6937 origin[1] = atof(Cmd_Argv(2));
6939 else if (!strcmp(Cmd_Argv(1), "originz"))
6941 if (Cmd_Argc() != 3)
6943 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6946 origin[2] = atof(Cmd_Argv(2));
6948 else if (!strcmp(Cmd_Argv(1), "move"))
6950 if (Cmd_Argc() != 5)
6952 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6955 origin[0] += atof(Cmd_Argv(2));
6956 origin[1] += atof(Cmd_Argv(3));
6957 origin[2] += atof(Cmd_Argv(4));
6959 else if (!strcmp(Cmd_Argv(1), "movex"))
6961 if (Cmd_Argc() != 3)
6963 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6966 origin[0] += atof(Cmd_Argv(2));
6968 else if (!strcmp(Cmd_Argv(1), "movey"))
6970 if (Cmd_Argc() != 3)
6972 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6975 origin[1] += atof(Cmd_Argv(2));
6977 else if (!strcmp(Cmd_Argv(1), "movez"))
6979 if (Cmd_Argc() != 3)
6981 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6984 origin[2] += atof(Cmd_Argv(2));
6986 else if (!strcmp(Cmd_Argv(1), "angles"))
6988 if (Cmd_Argc() != 5)
6990 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6993 angles[0] = atof(Cmd_Argv(2));
6994 angles[1] = atof(Cmd_Argv(3));
6995 angles[2] = atof(Cmd_Argv(4));
6997 else if (!strcmp(Cmd_Argv(1), "anglesx"))
6999 if (Cmd_Argc() != 3)
7001 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7004 angles[0] = atof(Cmd_Argv(2));
7006 else if (!strcmp(Cmd_Argv(1), "anglesy"))
7008 if (Cmd_Argc() != 3)
7010 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7013 angles[1] = atof(Cmd_Argv(2));
7015 else if (!strcmp(Cmd_Argv(1), "anglesz"))
7017 if (Cmd_Argc() != 3)
7019 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7022 angles[2] = atof(Cmd_Argv(2));
7024 else if (!strcmp(Cmd_Argv(1), "color"))
7026 if (Cmd_Argc() != 5)
7028 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
7031 color[0] = atof(Cmd_Argv(2));
7032 color[1] = atof(Cmd_Argv(3));
7033 color[2] = atof(Cmd_Argv(4));
7035 else if (!strcmp(Cmd_Argv(1), "radius"))
7037 if (Cmd_Argc() != 3)
7039 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7042 radius = atof(Cmd_Argv(2));
7044 else if (!strcmp(Cmd_Argv(1), "colorscale"))
7046 if (Cmd_Argc() == 3)
7048 double scale = atof(Cmd_Argv(2));
7055 if (Cmd_Argc() != 5)
7057 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
7060 color[0] *= atof(Cmd_Argv(2));
7061 color[1] *= atof(Cmd_Argv(3));
7062 color[2] *= atof(Cmd_Argv(4));
7065 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
7067 if (Cmd_Argc() != 3)
7069 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7072 radius *= atof(Cmd_Argv(2));
7074 else if (!strcmp(Cmd_Argv(1), "style"))
7076 if (Cmd_Argc() != 3)
7078 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7081 style = atoi(Cmd_Argv(2));
7083 else if (!strcmp(Cmd_Argv(1), "cubemap"))
7087 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7090 if (Cmd_Argc() == 3)
7091 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
7095 else if (!strcmp(Cmd_Argv(1), "shadows"))
7097 if (Cmd_Argc() != 3)
7099 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7102 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7104 else if (!strcmp(Cmd_Argv(1), "corona"))
7106 if (Cmd_Argc() != 3)
7108 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7111 corona = atof(Cmd_Argv(2));
7113 else if (!strcmp(Cmd_Argv(1), "coronasize"))
7115 if (Cmd_Argc() != 3)
7117 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7120 coronasizescale = atof(Cmd_Argv(2));
7122 else if (!strcmp(Cmd_Argv(1), "ambient"))
7124 if (Cmd_Argc() != 3)
7126 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7129 ambientscale = atof(Cmd_Argv(2));
7131 else if (!strcmp(Cmd_Argv(1), "diffuse"))
7133 if (Cmd_Argc() != 3)
7135 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7138 diffusescale = atof(Cmd_Argv(2));
7140 else if (!strcmp(Cmd_Argv(1), "specular"))
7142 if (Cmd_Argc() != 3)
7144 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7147 specularscale = atof(Cmd_Argv(2));
7149 else if (!strcmp(Cmd_Argv(1), "normalmode"))
7151 if (Cmd_Argc() != 3)
7153 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7156 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7158 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
7160 if (Cmd_Argc() != 3)
7162 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7165 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7169 Con_Print("usage: r_editlights_edit [property] [value]\n");
7170 Con_Print("Selected light's properties:\n");
7171 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7172 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7173 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7174 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
7175 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
7176 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
7177 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
7178 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
7179 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
7180 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
7181 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
7182 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
7183 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
7184 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
7187 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
7188 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
7191 static void R_Shadow_EditLights_EditAll_f(void)
7194 dlight_t *light, *oldselected;
7197 if (!r_editlights.integer)
7199 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
7203 oldselected = r_shadow_selectedlight;
7204 // EditLights doesn't seem to have a "remove" command or something so:
7205 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7206 for (lightindex = 0;lightindex < range;lightindex++)
7208 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7211 R_Shadow_SelectLight(light);
7212 R_Shadow_EditLights_Edit_f();
7214 // return to old selected (to not mess editing once selection is locked)
7215 R_Shadow_SelectLight(oldselected);
7218 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
7220 int lightnumber, lightcount;
7221 size_t lightindex, range;
7226 if (!r_editlights.integer)
7229 // update cvars so QC can query them
7230 if (r_shadow_selectedlight)
7232 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7233 Cvar_SetQuick(&r_editlights_current_origin, temp);
7234 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7235 Cvar_SetQuick(&r_editlights_current_angles, temp);
7236 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7237 Cvar_SetQuick(&r_editlights_current_color, temp);
7238 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
7239 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
7240 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
7241 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
7242 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
7243 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
7244 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
7245 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
7246 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
7247 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
7248 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
7251 // draw properties on screen
7252 if (!r_editlights_drawproperties.integer)
7254 x = vid_conwidth.value - 320;
7256 DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
7259 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7260 for (lightindex = 0;lightindex < range;lightindex++)
7262 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7265 if (light == r_shadow_selectedlight)
7266 lightnumber = (int)lightindex;
7269 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;
7270 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;
7272 if (r_shadow_selectedlight == NULL)
7274 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;
7275 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;
7276 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;
7277 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;
7278 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;
7279 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;
7280 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;
7281 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;
7282 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;
7283 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;
7284 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;
7285 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;
7286 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;
7287 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;
7288 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;
7290 dpsnprintf(temp, sizeof(temp), "Render stats\n"); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7291 dpsnprintf(temp, sizeof(temp), "Current color: %.3f %.3f %.3f\n", r_shadow_selectedlight->rtlight.currentcolor[0], r_shadow_selectedlight->rtlight.currentcolor[1], r_shadow_selectedlight->rtlight.currentcolor[2]); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7292 dpsnprintf(temp, sizeof(temp), "Shadow size : %ix%ix6\n", r_shadow_selectedlight->rtlight.shadowmapatlassidesize, r_shadow_selectedlight->rtlight.shadowmapatlassidesize); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7293 dpsnprintf(temp, sizeof(temp), "World surfs : %i\n", r_shadow_selectedlight->rtlight.cached_numsurfaces); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7294 dpsnprintf(temp, sizeof(temp), "Shadow ents : %i + %i noself\n", r_shadow_selectedlight->rtlight.cached_numshadowentities, r_shadow_selectedlight->rtlight.cached_numshadowentities_noselfshadow); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7295 dpsnprintf(temp, sizeof(temp), "Lit ents : %i + %i noself\n", r_shadow_selectedlight->rtlight.cached_numlightentities, r_shadow_selectedlight->rtlight.cached_numlightentities_noselfshadow); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7296 dpsnprintf(temp, sizeof(temp), "BG photons : %.3f\n", r_shadow_selectedlight->rtlight.bouncegrid_photons); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7297 dpsnprintf(temp, sizeof(temp), "BG radius : %.0f\n", r_shadow_selectedlight->rtlight.bouncegrid_effectiveradius); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7298 dpsnprintf(temp, sizeof(temp), "BG color : %.3f %.3f %.3f\n", r_shadow_selectedlight->rtlight.bouncegrid_photoncolor[0], r_shadow_selectedlight->rtlight.bouncegrid_photoncolor[1], r_shadow_selectedlight->rtlight.bouncegrid_photoncolor[2]); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7299 dpsnprintf(temp, sizeof(temp), "BG stats : %i traces %i hits\n", r_shadow_selectedlight->rtlight.bouncegrid_traces, r_shadow_selectedlight->rtlight.bouncegrid_hits); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7302 static void R_Shadow_EditLights_ToggleShadow_f(void)
7304 if (!r_editlights.integer)
7306 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7309 if (!r_shadow_selectedlight)
7311 Con_Print("No selected light.\n");
7314 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);
7317 static void R_Shadow_EditLights_ToggleCorona_f(void)
7319 if (!r_editlights.integer)
7321 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7324 if (!r_shadow_selectedlight)
7326 Con_Print("No selected light.\n");
7329 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);
7332 static void R_Shadow_EditLights_Remove_f(void)
7334 if (!r_editlights.integer)
7336 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
7339 if (!r_shadow_selectedlight)
7341 Con_Print("No selected light.\n");
7344 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
7345 r_shadow_selectedlight = NULL;
7348 static void R_Shadow_EditLights_Help_f(void)
7351 "Documentation on r_editlights system:\n"
7353 "r_editlights : enable/disable editing mode\n"
7354 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
7355 "r_editlights_cursorpushback : push back cursor this far from surface\n"
7356 "r_editlights_cursorpushoff : push cursor off surface this far\n"
7357 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
7358 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
7360 "r_editlights_help : this help\n"
7361 "r_editlights_clear : remove all lights\n"
7362 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
7363 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
7364 "r_editlights_save : save to .rtlights file\n"
7365 "r_editlights_spawn : create a light with default settings\n"
7366 "r_editlights_edit command : edit selected light - more documentation below\n"
7367 "r_editlights_remove : remove selected light\n"
7368 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
7369 "r_editlights_importlightentitiesfrommap : reload light entities\n"
7370 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
7372 "origin x y z : set light location\n"
7373 "originx x: set x component of light location\n"
7374 "originy y: set y component of light location\n"
7375 "originz z: set z component of light location\n"
7376 "move x y z : adjust light location\n"
7377 "movex x: adjust x component of light location\n"
7378 "movey y: adjust y component of light location\n"
7379 "movez z: adjust z component of light location\n"
7380 "angles x y z : set light angles\n"
7381 "anglesx x: set x component of light angles\n"
7382 "anglesy y: set y component of light angles\n"
7383 "anglesz z: set z component of light angles\n"
7384 "color r g b : set color of light (can be brighter than 1 1 1)\n"
7385 "radius radius : set radius (size) of light\n"
7386 "colorscale grey : multiply color of light (1 does nothing)\n"
7387 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
7388 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
7389 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
7390 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
7391 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
7392 "cubemap basename : set filter cubemap of light\n"
7393 "shadows 1/0 : turn on/off shadows\n"
7394 "corona n : set corona intensity\n"
7395 "coronasize n : set corona size (0-1)\n"
7396 "ambient n : set ambient intensity (0-1)\n"
7397 "diffuse n : set diffuse intensity (0-1)\n"
7398 "specular n : set specular intensity (0-1)\n"
7399 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
7400 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
7401 "<nothing> : print light properties to console\n"
7405 static void R_Shadow_EditLights_CopyInfo_f(void)
7407 if (!r_editlights.integer)
7409 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
7412 if (!r_shadow_selectedlight)
7414 Con_Print("No selected light.\n");
7417 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
7418 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
7419 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
7420 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
7421 if (r_shadow_selectedlight->cubemapname)
7422 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
7424 r_shadow_bufferlight.cubemapname[0] = 0;
7425 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
7426 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
7427 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
7428 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
7429 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
7430 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
7431 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
7434 static void R_Shadow_EditLights_PasteInfo_f(void)
7436 if (!r_editlights.integer)
7438 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
7441 if (!r_shadow_selectedlight)
7443 Con_Print("No selected light.\n");
7446 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);
7449 static void R_Shadow_EditLights_Lock_f(void)
7451 if (!r_editlights.integer)
7453 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
7456 if (r_editlights_lockcursor)
7458 r_editlights_lockcursor = false;
7461 if (!r_shadow_selectedlight)
7463 Con_Print("No selected light to lock on.\n");
7466 r_editlights_lockcursor = true;
7469 static void R_Shadow_EditLights_Init(void)
7471 Cvar_RegisterVariable(&r_editlights);
7472 Cvar_RegisterVariable(&r_editlights_cursordistance);
7473 Cvar_RegisterVariable(&r_editlights_cursorpushback);
7474 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
7475 Cvar_RegisterVariable(&r_editlights_cursorgrid);
7476 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
7477 Cvar_RegisterVariable(&r_editlights_drawproperties);
7478 Cvar_RegisterVariable(&r_editlights_current_origin);
7479 Cvar_RegisterVariable(&r_editlights_current_angles);
7480 Cvar_RegisterVariable(&r_editlights_current_color);
7481 Cvar_RegisterVariable(&r_editlights_current_radius);
7482 Cvar_RegisterVariable(&r_editlights_current_corona);
7483 Cvar_RegisterVariable(&r_editlights_current_coronasize);
7484 Cvar_RegisterVariable(&r_editlights_current_style);
7485 Cvar_RegisterVariable(&r_editlights_current_shadows);
7486 Cvar_RegisterVariable(&r_editlights_current_cubemap);
7487 Cvar_RegisterVariable(&r_editlights_current_ambient);
7488 Cvar_RegisterVariable(&r_editlights_current_diffuse);
7489 Cvar_RegisterVariable(&r_editlights_current_specular);
7490 Cvar_RegisterVariable(&r_editlights_current_normalmode);
7491 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
7492 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
7493 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
7494 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)");
7495 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
7496 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
7497 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
7498 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)");
7499 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
7500 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
7501 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
7502 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
7503 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
7504 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
7505 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)");
7506 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
7512 =============================================================================
7516 =============================================================================
7519 void R_LightPoint(float *color, const vec3_t p, const int flags)
7521 int i, numlights, flag;
7522 float f, relativepoint[3], dist, dist2, lightradius2;
7527 if (r_fullbright.integer)
7529 VectorSet(color, 1, 1, 1);
7535 if (flags & LP_LIGHTMAP)
7537 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7539 VectorClear(diffuse);
7540 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, color, diffuse, n);
7541 VectorAdd(color, diffuse, color);
7544 VectorSet(color, 1, 1, 1);
7545 color[0] += r_refdef.scene.ambient;
7546 color[1] += r_refdef.scene.ambient;
7547 color[2] += r_refdef.scene.ambient;
7550 if (flags & LP_RTWORLD)
7552 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7553 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7554 for (i = 0; i < numlights; i++)
7556 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7559 light = &dlight->rtlight;
7560 if (!(light->flags & flag))
7563 lightradius2 = light->radius * light->radius;
7564 VectorSubtract(light->shadoworigin, p, relativepoint);
7565 dist2 = VectorLength2(relativepoint);
7566 if (dist2 >= lightradius2)
7568 dist = sqrt(dist2) / light->radius;
7569 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7572 // todo: add to both ambient and diffuse
7573 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1)
7574 VectorMA(color, f, light->currentcolor, color);
7577 if (flags & LP_DYNLIGHT)
7580 for (i = 0;i < r_refdef.scene.numlights;i++)
7582 light = r_refdef.scene.lights[i];
7584 lightradius2 = light->radius * light->radius;
7585 VectorSubtract(light->shadoworigin, p, relativepoint);
7586 dist2 = VectorLength2(relativepoint);
7587 if (dist2 >= lightradius2)
7589 dist = sqrt(dist2) / light->radius;
7590 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7593 // todo: add to both ambient and diffuse
7594 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1)
7595 VectorMA(color, f, light->color, color);
7600 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
7602 int i, numlights, flag;
7605 float relativepoint[3];
7614 if (r_fullbright.integer)
7616 VectorSet(ambient, 1, 1, 1);
7617 VectorClear(diffuse);
7618 VectorClear(lightdir);
7622 if (flags == LP_LIGHTMAP)
7624 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7625 VectorClear(diffuse);
7626 VectorClear(lightdir);
7627 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7628 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
7630 VectorSet(ambient, 1, 1, 1);
7634 memset(sample, 0, sizeof(sample));
7635 VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7637 if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7640 VectorClear(tempambient);
7642 VectorClear(relativepoint);
7643 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
7644 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
7645 VectorScale(color, r_refdef.lightmapintensity, color);
7646 VectorAdd(sample, tempambient, sample);
7647 VectorMA(sample , 0.5f , color, sample );
7648 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7649 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7650 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7651 // calculate a weighted average light direction as well
7652 intensity = VectorLength(color);
7653 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7656 if (flags & LP_RTWORLD)
7658 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7659 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7660 for (i = 0; i < numlights; i++)
7662 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7665 light = &dlight->rtlight;
7666 if (!(light->flags & flag))
7669 lightradius2 = light->radius * light->radius;
7670 VectorSubtract(light->shadoworigin, p, relativepoint);
7671 dist2 = VectorLength2(relativepoint);
7672 if (dist2 >= lightradius2)
7674 dist = sqrt(dist2) / light->radius;
7675 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
7676 if (intensity <= 0.0f)
7678 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
7680 // scale down intensity to add to both ambient and diffuse
7681 //intensity *= 0.5f;
7682 VectorNormalize(relativepoint);
7683 VectorScale(light->currentcolor, intensity, color);
7684 VectorMA(sample , 0.5f , color, sample );
7685 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7686 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7687 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7688 // calculate a weighted average light direction as well
7689 intensity *= VectorLength(color);
7690 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7692 // FIXME: sample bouncegrid too!
7695 if (flags & LP_DYNLIGHT)
7698 for (i = 0;i < r_refdef.scene.numlights;i++)
7700 light = r_refdef.scene.lights[i];
7702 lightradius2 = light->radius * light->radius;
7703 VectorSubtract(light->shadoworigin, p, relativepoint);
7704 dist2 = VectorLength2(relativepoint);
7705 if (dist2 >= lightradius2)
7707 dist = sqrt(dist2) / light->radius;
7708 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
7709 if (intensity <= 0.0f)
7711 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
7713 // scale down intensity to add to both ambient and diffuse
7714 //intensity *= 0.5f;
7715 VectorNormalize(relativepoint);
7716 VectorScale(light->currentcolor, intensity, color);
7717 VectorMA(sample , 0.5f , color, sample );
7718 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7719 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7720 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7721 // calculate a weighted average light direction as well
7722 intensity *= VectorLength(color);
7723 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7727 // calculate the direction we'll use to reduce the sample to a directional light source
7728 VectorCopy(sample + 12, dir);
7729 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
7730 VectorNormalize(dir);
7731 // extract the diffuse color along the chosen direction and scale it
7732 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
7733 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
7734 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
7735 // subtract some of diffuse from ambient
7736 VectorMA(sample, -0.333f, diffuse, ambient);
7737 // store the normalized lightdir
7738 VectorCopy(dir, lightdir);