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_GL20:
5939 case RENDERPATH_GLES1:
5940 case RENDERPATH_GLES2:
5941 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5942 // See if we can use the GPU-side method to prevent implicit sync
5943 if (vid.support.arb_query_buffer_object) {
5944 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
5945 if (!r_shadow_occlusion_buf) {
5946 qglGenBuffersARB(1, &r_shadow_occlusion_buf);
5947 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5948 qglBufferDataARB(GL_QUERY_BUFFER_ARB, 8, NULL, GL_DYNAMIC_COPY);
5950 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5952 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(0));
5953 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4));
5954 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
5955 occlude = MATERIALFLAG_OCCLUDE;
5956 cscale *= rtlight->corona_visibility;
5964 case RENDERPATH_GL11:
5965 case RENDERPATH_GL13:
5966 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5968 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5969 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5970 if (visiblepixels < 1 || allpixels < 1)
5972 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5973 cscale *= rtlight->corona_visibility;
5979 case RENDERPATH_D3D9:
5980 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5982 case RENDERPATH_D3D10:
5983 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5985 case RENDERPATH_D3D11:
5986 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5988 case RENDERPATH_SOFT:
5989 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5997 // FIXME: these traces should scan all render entities instead of cl.world
5998 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)
6001 VectorScale(rtlight->currentcolor, cscale, color);
6002 if (VectorLength(color) > (1.0f / 256.0f))
6005 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
6008 VectorNegate(color, color);
6009 GL_BlendEquationSubtract(true);
6011 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
6012 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);
6013 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
6015 GL_BlendEquationSubtract(false);
6019 void R_Shadow_DrawCoronas(void)
6022 qboolean usequery = false;
6027 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
6029 if (r_fb.water.renderingscene)
6031 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6032 R_EntityMatrix(&identitymatrix);
6034 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6036 // check occlusion of coronas
6037 // use GL_ARB_occlusion_query if available
6038 // otherwise use raytraces
6040 switch (vid.renderpath)
6042 case RENDERPATH_GL11:
6043 case RENDERPATH_GL13:
6044 case RENDERPATH_GL20:
6045 case RENDERPATH_GLES1:
6046 case RENDERPATH_GLES2:
6047 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
6048 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
6051 GL_ColorMask(0,0,0,0);
6052 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
6053 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
6056 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
6057 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
6059 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
6062 RSurf_ActiveWorldEntity();
6063 GL_BlendFunc(GL_ONE, GL_ZERO);
6064 GL_CullFace(GL_NONE);
6065 GL_DepthMask(false);
6066 GL_DepthRange(0, 1);
6067 GL_PolygonOffset(0, 0);
6069 R_Mesh_ResetTextureState();
6070 R_SetupShader_Generic_NoTexture(false, false);
6074 case RENDERPATH_D3D9:
6076 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6078 case RENDERPATH_D3D10:
6079 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6081 case RENDERPATH_D3D11:
6082 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6084 case RENDERPATH_SOFT:
6086 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6089 for (lightindex = 0;lightindex < range;lightindex++)
6091 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6094 rtlight = &light->rtlight;
6095 rtlight->corona_visibility = 0;
6096 rtlight->corona_queryindex_visiblepixels = 0;
6097 rtlight->corona_queryindex_allpixels = 0;
6098 if (!(rtlight->flags & flag))
6100 if (rtlight->corona <= 0)
6102 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
6104 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6106 for (i = 0;i < r_refdef.scene.numlights;i++)
6108 rtlight = r_refdef.scene.lights[i];
6109 rtlight->corona_visibility = 0;
6110 rtlight->corona_queryindex_visiblepixels = 0;
6111 rtlight->corona_queryindex_allpixels = 0;
6112 if (!(rtlight->flags & flag))
6114 if (rtlight->corona <= 0)
6116 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6119 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
6121 // now draw the coronas using the query data for intensity info
6122 for (lightindex = 0;lightindex < range;lightindex++)
6124 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6127 rtlight = &light->rtlight;
6128 if (rtlight->corona_visibility <= 0)
6130 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6132 for (i = 0;i < r_refdef.scene.numlights;i++)
6134 rtlight = r_refdef.scene.lights[i];
6135 if (rtlight->corona_visibility <= 0)
6137 if (gl_flashblend.integer)
6138 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
6140 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6146 static dlight_t *R_Shadow_NewWorldLight(void)
6148 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
6151 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)
6155 // 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
6157 // validate parameters
6161 // copy to light properties
6162 VectorCopy(origin, light->origin);
6163 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
6164 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
6165 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
6167 light->color[0] = max(color[0], 0);
6168 light->color[1] = max(color[1], 0);
6169 light->color[2] = max(color[2], 0);
6171 light->color[0] = color[0];
6172 light->color[1] = color[1];
6173 light->color[2] = color[2];
6174 light->radius = max(radius, 0);
6175 light->style = style;
6176 light->shadow = shadowenable;
6177 light->corona = corona;
6178 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
6179 light->coronasizescale = coronasizescale;
6180 light->ambientscale = ambientscale;
6181 light->diffusescale = diffusescale;
6182 light->specularscale = specularscale;
6183 light->flags = flags;
6185 // update renderable light data
6186 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
6187 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);
6190 static void R_Shadow_FreeWorldLight(dlight_t *light)
6192 if (r_shadow_selectedlight == light)
6193 r_shadow_selectedlight = NULL;
6194 R_RTLight_Uncompile(&light->rtlight);
6195 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
6198 void R_Shadow_ClearWorldLights(void)
6202 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6203 for (lightindex = 0;lightindex < range;lightindex++)
6205 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6207 R_Shadow_FreeWorldLight(light);
6209 r_shadow_selectedlight = NULL;
6212 static void R_Shadow_SelectLight(dlight_t *light)
6214 if (r_shadow_selectedlight)
6215 r_shadow_selectedlight->selected = false;
6216 r_shadow_selectedlight = light;
6217 if (r_shadow_selectedlight)
6218 r_shadow_selectedlight->selected = true;
6221 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6223 // this is never batched (there can be only one)
6225 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
6226 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6227 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6230 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6235 skinframe_t *skinframe;
6238 // this is never batched (due to the ent parameter changing every time)
6239 // so numsurfaces == 1 and surfacelist[0] == lightnumber
6240 const dlight_t *light = (dlight_t *)ent;
6243 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
6246 VectorScale(light->color, intensity, spritecolor);
6247 if (VectorLength(spritecolor) < 0.1732f)
6248 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
6249 if (VectorLength(spritecolor) > 1.0f)
6250 VectorNormalize(spritecolor);
6252 // draw light sprite
6253 if (light->cubemapname[0] && !light->shadow)
6254 skinframe = r_editlights_sprcubemapnoshadowlight;
6255 else if (light->cubemapname[0])
6256 skinframe = r_editlights_sprcubemaplight;
6257 else if (!light->shadow)
6258 skinframe = r_editlights_sprnoshadowlight;
6260 skinframe = r_editlights_sprlight;
6262 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);
6263 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6265 // draw selection sprite if light is selected
6266 if (light->selected)
6268 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6269 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6270 // VorteX todo: add normalmode/realtime mode light overlay sprites?
6274 void R_Shadow_DrawLightSprites(void)
6278 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6279 for (lightindex = 0;lightindex < range;lightindex++)
6281 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6283 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
6285 if (!r_editlights_lockcursor)
6286 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
6289 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
6294 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6295 if (lightindex >= range)
6297 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6300 rtlight = &light->rtlight;
6301 //if (!(rtlight->flags & flag))
6303 VectorCopy(rtlight->shadoworigin, origin);
6304 *radius = rtlight->radius;
6305 VectorCopy(rtlight->color, color);
6309 static void R_Shadow_SelectLightInView(void)
6311 float bestrating, rating, temp[3];
6315 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6319 if (r_editlights_lockcursor)
6321 for (lightindex = 0;lightindex < range;lightindex++)
6323 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6326 VectorSubtract(light->origin, r_refdef.view.origin, temp);
6327 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
6330 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
6331 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)
6333 bestrating = rating;
6338 R_Shadow_SelectLight(best);
6341 void R_Shadow_LoadWorldLights(void)
6343 int n, a, style, shadow, flags;
6344 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
6345 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
6346 if (cl.worldmodel == NULL)
6348 Con_Print("No map loaded.\n");
6351 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6352 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6362 for (;COM_Parse(t, true) && strcmp(
6363 if (COM_Parse(t, true))
6365 if (com_token[0] == '!')
6368 origin[0] = atof(com_token+1);
6371 origin[0] = atof(com_token);
6376 while (*s && *s != '\n' && *s != '\r')
6382 // check for modifier flags
6389 #if _MSC_VER >= 1400
6390 #define sscanf sscanf_s
6392 cubemapname[sizeof(cubemapname)-1] = 0;
6393 #if MAX_QPATH != 128
6394 #error update this code if MAX_QPATH changes
6396 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
6397 #if _MSC_VER >= 1400
6398 , sizeof(cubemapname)
6400 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
6403 flags = LIGHTFLAG_REALTIMEMODE;
6411 coronasizescale = 0.25f;
6413 VectorClear(angles);
6416 if (a < 9 || !strcmp(cubemapname, "\"\""))
6418 // remove quotes on cubemapname
6419 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
6422 namelen = strlen(cubemapname) - 2;
6423 memmove(cubemapname, cubemapname + 1, namelen);
6424 cubemapname[namelen] = '\0';
6428 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);
6431 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6439 Con_Printf("invalid rtlights file \"%s\"\n", name);
6440 Mem_Free(lightsstring);
6444 void R_Shadow_SaveWorldLights(void)
6448 size_t bufchars, bufmaxchars;
6450 char name[MAX_QPATH];
6451 char line[MAX_INPUTLINE];
6452 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
6453 // I hate lines which are 3 times my screen size :( --blub
6456 if (cl.worldmodel == NULL)
6458 Con_Print("No map loaded.\n");
6461 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6462 bufchars = bufmaxchars = 0;
6464 for (lightindex = 0;lightindex < range;lightindex++)
6466 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6469 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
6470 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);
6471 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
6472 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]);
6474 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);
6475 if (bufchars + strlen(line) > bufmaxchars)
6477 bufmaxchars = bufchars + strlen(line) + 2048;
6479 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
6483 memcpy(buf, oldbuf, bufchars);
6489 memcpy(buf + bufchars, line, strlen(line));
6490 bufchars += strlen(line);
6494 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
6499 void R_Shadow_LoadLightsFile(void)
6502 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
6503 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
6504 if (cl.worldmodel == NULL)
6506 Con_Print("No map loaded.\n");
6509 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
6510 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6518 while (*s && *s != '\n' && *s != '\r')
6524 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);
6528 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);
6531 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
6532 radius = bound(15, radius, 4096);
6533 VectorScale(color, (2.0f / (8388608.0f)), color);
6534 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6542 Con_Printf("invalid lights file \"%s\"\n", name);
6543 Mem_Free(lightsstring);
6547 // tyrlite/hmap2 light types in the delay field
6548 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
6550 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
6562 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
6563 char key[256], value[MAX_INPUTLINE];
6566 if (cl.worldmodel == NULL)
6568 Con_Print("No map loaded.\n");
6571 // try to load a .ent file first
6572 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
6573 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
6574 // and if that is not found, fall back to the bsp file entity string
6576 data = cl.worldmodel->brush.entities;
6579 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
6581 type = LIGHTTYPE_MINUSX;
6582 origin[0] = origin[1] = origin[2] = 0;
6583 originhack[0] = originhack[1] = originhack[2] = 0;
6584 angles[0] = angles[1] = angles[2] = 0;
6585 color[0] = color[1] = color[2] = 1;
6586 light[0] = light[1] = light[2] = 1;light[3] = 300;
6587 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
6597 if (!COM_ParseToken_Simple(&data, false, false, true))
6599 if (com_token[0] == '}')
6600 break; // end of entity
6601 if (com_token[0] == '_')
6602 strlcpy(key, com_token + 1, sizeof(key));
6604 strlcpy(key, com_token, sizeof(key));
6605 while (key[strlen(key)-1] == ' ') // remove trailing spaces
6606 key[strlen(key)-1] = 0;
6607 if (!COM_ParseToken_Simple(&data, false, false, true))
6609 strlcpy(value, com_token, sizeof(value));
6611 // now that we have the key pair worked out...
6612 if (!strcmp("light", key))
6614 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
6618 light[0] = vec[0] * (1.0f / 256.0f);
6619 light[1] = vec[0] * (1.0f / 256.0f);
6620 light[2] = vec[0] * (1.0f / 256.0f);
6626 light[0] = vec[0] * (1.0f / 255.0f);
6627 light[1] = vec[1] * (1.0f / 255.0f);
6628 light[2] = vec[2] * (1.0f / 255.0f);
6632 else if (!strcmp("delay", key))
6634 else if (!strcmp("origin", key))
6635 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
6636 else if (!strcmp("angle", key))
6637 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
6638 else if (!strcmp("angles", key))
6639 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
6640 else if (!strcmp("color", key))
6641 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
6642 else if (!strcmp("wait", key))
6643 fadescale = atof(value);
6644 else if (!strcmp("classname", key))
6646 if (!strncmp(value, "light", 5))
6649 if (!strcmp(value, "light_fluoro"))
6654 overridecolor[0] = 1;
6655 overridecolor[1] = 1;
6656 overridecolor[2] = 1;
6658 if (!strcmp(value, "light_fluorospark"))
6663 overridecolor[0] = 1;
6664 overridecolor[1] = 1;
6665 overridecolor[2] = 1;
6667 if (!strcmp(value, "light_globe"))
6672 overridecolor[0] = 1;
6673 overridecolor[1] = 0.8;
6674 overridecolor[2] = 0.4;
6676 if (!strcmp(value, "light_flame_large_yellow"))
6681 overridecolor[0] = 1;
6682 overridecolor[1] = 0.5;
6683 overridecolor[2] = 0.1;
6685 if (!strcmp(value, "light_flame_small_yellow"))
6690 overridecolor[0] = 1;
6691 overridecolor[1] = 0.5;
6692 overridecolor[2] = 0.1;
6694 if (!strcmp(value, "light_torch_small_white"))
6699 overridecolor[0] = 1;
6700 overridecolor[1] = 0.5;
6701 overridecolor[2] = 0.1;
6703 if (!strcmp(value, "light_torch_small_walltorch"))
6708 overridecolor[0] = 1;
6709 overridecolor[1] = 0.5;
6710 overridecolor[2] = 0.1;
6714 else if (!strcmp("style", key))
6715 style = atoi(value);
6716 else if (!strcmp("skin", key))
6717 skin = (int)atof(value);
6718 else if (!strcmp("pflags", key))
6719 pflags = (int)atof(value);
6720 //else if (!strcmp("effects", key))
6721 // effects = (int)atof(value);
6722 else if (cl.worldmodel->type == mod_brushq3)
6724 if (!strcmp("scale", key))
6725 lightscale = atof(value);
6726 if (!strcmp("fade", key))
6727 fadescale = atof(value);
6732 if (lightscale <= 0)
6736 if (color[0] == color[1] && color[0] == color[2])
6738 color[0] *= overridecolor[0];
6739 color[1] *= overridecolor[1];
6740 color[2] *= overridecolor[2];
6742 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
6743 color[0] = color[0] * light[0];
6744 color[1] = color[1] * light[1];
6745 color[2] = color[2] * light[2];
6748 case LIGHTTYPE_MINUSX:
6750 case LIGHTTYPE_RECIPX:
6752 VectorScale(color, (1.0f / 16.0f), color);
6754 case LIGHTTYPE_RECIPXX:
6756 VectorScale(color, (1.0f / 16.0f), color);
6759 case LIGHTTYPE_NONE:
6763 case LIGHTTYPE_MINUSXX:
6766 VectorAdd(origin, originhack, origin);
6768 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);
6771 Mem_Free(entfiledata);
6775 static void R_Shadow_SetCursorLocationForView(void)
6778 vec3_t dest, endpos;
6780 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
6781 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true);
6782 if (trace.fraction < 1)
6784 dist = trace.fraction * r_editlights_cursordistance.value;
6785 push = r_editlights_cursorpushback.value;
6789 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
6790 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
6794 VectorClear( endpos );
6796 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6797 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6798 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6801 void R_Shadow_UpdateWorldLightSelection(void)
6803 if (r_editlights.integer)
6805 R_Shadow_SetCursorLocationForView();
6806 R_Shadow_SelectLightInView();
6809 R_Shadow_SelectLight(NULL);
6812 static void R_Shadow_EditLights_Clear_f(void)
6814 R_Shadow_ClearWorldLights();
6817 void R_Shadow_EditLights_Reload_f(void)
6821 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
6822 R_Shadow_ClearWorldLights();
6823 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
6825 R_Shadow_LoadWorldLights();
6826 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6827 R_Shadow_LoadLightsFile();
6829 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
6831 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6832 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6836 static void R_Shadow_EditLights_Save_f(void)
6840 R_Shadow_SaveWorldLights();
6843 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6845 R_Shadow_ClearWorldLights();
6846 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6849 static void R_Shadow_EditLights_ImportLightsFile_f(void)
6851 R_Shadow_ClearWorldLights();
6852 R_Shadow_LoadLightsFile();
6855 static void R_Shadow_EditLights_Spawn_f(void)
6858 if (!r_editlights.integer)
6860 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6863 if (Cmd_Argc() != 1)
6865 Con_Print("r_editlights_spawn does not take parameters\n");
6868 color[0] = color[1] = color[2] = 1;
6869 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6872 static void R_Shadow_EditLights_Edit_f(void)
6874 vec3_t origin, angles, color;
6875 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6876 int style, shadows, flags, normalmode, realtimemode;
6877 char cubemapname[MAX_INPUTLINE];
6878 if (!r_editlights.integer)
6880 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6883 if (!r_shadow_selectedlight)
6885 Con_Print("No selected light.\n");
6888 VectorCopy(r_shadow_selectedlight->origin, origin);
6889 VectorCopy(r_shadow_selectedlight->angles, angles);
6890 VectorCopy(r_shadow_selectedlight->color, color);
6891 radius = r_shadow_selectedlight->radius;
6892 style = r_shadow_selectedlight->style;
6893 if (r_shadow_selectedlight->cubemapname)
6894 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6897 shadows = r_shadow_selectedlight->shadow;
6898 corona = r_shadow_selectedlight->corona;
6899 coronasizescale = r_shadow_selectedlight->coronasizescale;
6900 ambientscale = r_shadow_selectedlight->ambientscale;
6901 diffusescale = r_shadow_selectedlight->diffusescale;
6902 specularscale = r_shadow_selectedlight->specularscale;
6903 flags = r_shadow_selectedlight->flags;
6904 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6905 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6906 if (!strcmp(Cmd_Argv(1), "origin"))
6908 if (Cmd_Argc() != 5)
6910 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6913 origin[0] = atof(Cmd_Argv(2));
6914 origin[1] = atof(Cmd_Argv(3));
6915 origin[2] = atof(Cmd_Argv(4));
6917 else if (!strcmp(Cmd_Argv(1), "originscale"))
6919 if (Cmd_Argc() != 5)
6921 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6924 origin[0] *= atof(Cmd_Argv(2));
6925 origin[1] *= atof(Cmd_Argv(3));
6926 origin[2] *= atof(Cmd_Argv(4));
6928 else if (!strcmp(Cmd_Argv(1), "originx"))
6930 if (Cmd_Argc() != 3)
6932 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6935 origin[0] = atof(Cmd_Argv(2));
6937 else if (!strcmp(Cmd_Argv(1), "originy"))
6939 if (Cmd_Argc() != 3)
6941 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6944 origin[1] = atof(Cmd_Argv(2));
6946 else if (!strcmp(Cmd_Argv(1), "originz"))
6948 if (Cmd_Argc() != 3)
6950 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6953 origin[2] = atof(Cmd_Argv(2));
6955 else if (!strcmp(Cmd_Argv(1), "move"))
6957 if (Cmd_Argc() != 5)
6959 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6962 origin[0] += atof(Cmd_Argv(2));
6963 origin[1] += atof(Cmd_Argv(3));
6964 origin[2] += atof(Cmd_Argv(4));
6966 else if (!strcmp(Cmd_Argv(1), "movex"))
6968 if (Cmd_Argc() != 3)
6970 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6973 origin[0] += atof(Cmd_Argv(2));
6975 else if (!strcmp(Cmd_Argv(1), "movey"))
6977 if (Cmd_Argc() != 3)
6979 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6982 origin[1] += atof(Cmd_Argv(2));
6984 else if (!strcmp(Cmd_Argv(1), "movez"))
6986 if (Cmd_Argc() != 3)
6988 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6991 origin[2] += atof(Cmd_Argv(2));
6993 else if (!strcmp(Cmd_Argv(1), "angles"))
6995 if (Cmd_Argc() != 5)
6997 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
7000 angles[0] = atof(Cmd_Argv(2));
7001 angles[1] = atof(Cmd_Argv(3));
7002 angles[2] = atof(Cmd_Argv(4));
7004 else if (!strcmp(Cmd_Argv(1), "anglesx"))
7006 if (Cmd_Argc() != 3)
7008 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7011 angles[0] = atof(Cmd_Argv(2));
7013 else if (!strcmp(Cmd_Argv(1), "anglesy"))
7015 if (Cmd_Argc() != 3)
7017 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7020 angles[1] = atof(Cmd_Argv(2));
7022 else if (!strcmp(Cmd_Argv(1), "anglesz"))
7024 if (Cmd_Argc() != 3)
7026 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7029 angles[2] = atof(Cmd_Argv(2));
7031 else if (!strcmp(Cmd_Argv(1), "color"))
7033 if (Cmd_Argc() != 5)
7035 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
7038 color[0] = atof(Cmd_Argv(2));
7039 color[1] = atof(Cmd_Argv(3));
7040 color[2] = atof(Cmd_Argv(4));
7042 else if (!strcmp(Cmd_Argv(1), "radius"))
7044 if (Cmd_Argc() != 3)
7046 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7049 radius = atof(Cmd_Argv(2));
7051 else if (!strcmp(Cmd_Argv(1), "colorscale"))
7053 if (Cmd_Argc() == 3)
7055 double scale = atof(Cmd_Argv(2));
7062 if (Cmd_Argc() != 5)
7064 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
7067 color[0] *= atof(Cmd_Argv(2));
7068 color[1] *= atof(Cmd_Argv(3));
7069 color[2] *= atof(Cmd_Argv(4));
7072 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
7074 if (Cmd_Argc() != 3)
7076 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7079 radius *= atof(Cmd_Argv(2));
7081 else if (!strcmp(Cmd_Argv(1), "style"))
7083 if (Cmd_Argc() != 3)
7085 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7088 style = atoi(Cmd_Argv(2));
7090 else if (!strcmp(Cmd_Argv(1), "cubemap"))
7094 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7097 if (Cmd_Argc() == 3)
7098 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
7102 else if (!strcmp(Cmd_Argv(1), "shadows"))
7104 if (Cmd_Argc() != 3)
7106 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7109 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7111 else if (!strcmp(Cmd_Argv(1), "corona"))
7113 if (Cmd_Argc() != 3)
7115 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7118 corona = atof(Cmd_Argv(2));
7120 else if (!strcmp(Cmd_Argv(1), "coronasize"))
7122 if (Cmd_Argc() != 3)
7124 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7127 coronasizescale = atof(Cmd_Argv(2));
7129 else if (!strcmp(Cmd_Argv(1), "ambient"))
7131 if (Cmd_Argc() != 3)
7133 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7136 ambientscale = atof(Cmd_Argv(2));
7138 else if (!strcmp(Cmd_Argv(1), "diffuse"))
7140 if (Cmd_Argc() != 3)
7142 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7145 diffusescale = atof(Cmd_Argv(2));
7147 else if (!strcmp(Cmd_Argv(1), "specular"))
7149 if (Cmd_Argc() != 3)
7151 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7154 specularscale = atof(Cmd_Argv(2));
7156 else if (!strcmp(Cmd_Argv(1), "normalmode"))
7158 if (Cmd_Argc() != 3)
7160 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7163 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7165 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
7167 if (Cmd_Argc() != 3)
7169 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7172 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7176 Con_Print("usage: r_editlights_edit [property] [value]\n");
7177 Con_Print("Selected light's properties:\n");
7178 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7179 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7180 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7181 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
7182 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
7183 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
7184 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
7185 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
7186 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
7187 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
7188 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
7189 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
7190 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
7191 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
7194 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
7195 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
7198 static void R_Shadow_EditLights_EditAll_f(void)
7201 dlight_t *light, *oldselected;
7204 if (!r_editlights.integer)
7206 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
7210 oldselected = r_shadow_selectedlight;
7211 // EditLights doesn't seem to have a "remove" command or something so:
7212 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7213 for (lightindex = 0;lightindex < range;lightindex++)
7215 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7218 R_Shadow_SelectLight(light);
7219 R_Shadow_EditLights_Edit_f();
7221 // return to old selected (to not mess editing once selection is locked)
7222 R_Shadow_SelectLight(oldselected);
7225 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
7227 int lightnumber, lightcount;
7228 size_t lightindex, range;
7233 if (!r_editlights.integer)
7236 // update cvars so QC can query them
7237 if (r_shadow_selectedlight)
7239 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7240 Cvar_SetQuick(&r_editlights_current_origin, temp);
7241 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7242 Cvar_SetQuick(&r_editlights_current_angles, temp);
7243 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7244 Cvar_SetQuick(&r_editlights_current_color, temp);
7245 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
7246 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
7247 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
7248 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
7249 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
7250 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
7251 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
7252 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
7253 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
7254 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
7255 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
7258 // draw properties on screen
7259 if (!r_editlights_drawproperties.integer)
7261 x = vid_conwidth.value - 320;
7263 DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
7266 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7267 for (lightindex = 0;lightindex < range;lightindex++)
7269 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7272 if (light == r_shadow_selectedlight)
7273 lightnumber = (int)lightindex;
7276 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;
7277 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;
7279 if (r_shadow_selectedlight == NULL)
7281 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;
7282 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;
7283 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;
7284 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;
7285 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;
7286 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;
7287 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;
7288 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;
7289 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;
7290 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;
7291 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;
7292 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;
7293 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;
7294 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;
7295 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;
7297 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;
7298 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;
7299 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;
7300 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;
7301 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;
7302 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;
7303 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;
7304 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;
7305 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;
7306 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;
7309 static void R_Shadow_EditLights_ToggleShadow_f(void)
7311 if (!r_editlights.integer)
7313 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7316 if (!r_shadow_selectedlight)
7318 Con_Print("No selected light.\n");
7321 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);
7324 static void R_Shadow_EditLights_ToggleCorona_f(void)
7326 if (!r_editlights.integer)
7328 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7331 if (!r_shadow_selectedlight)
7333 Con_Print("No selected light.\n");
7336 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);
7339 static void R_Shadow_EditLights_Remove_f(void)
7341 if (!r_editlights.integer)
7343 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
7346 if (!r_shadow_selectedlight)
7348 Con_Print("No selected light.\n");
7351 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
7352 r_shadow_selectedlight = NULL;
7355 static void R_Shadow_EditLights_Help_f(void)
7358 "Documentation on r_editlights system:\n"
7360 "r_editlights : enable/disable editing mode\n"
7361 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
7362 "r_editlights_cursorpushback : push back cursor this far from surface\n"
7363 "r_editlights_cursorpushoff : push cursor off surface this far\n"
7364 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
7365 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
7367 "r_editlights_help : this help\n"
7368 "r_editlights_clear : remove all lights\n"
7369 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
7370 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
7371 "r_editlights_save : save to .rtlights file\n"
7372 "r_editlights_spawn : create a light with default settings\n"
7373 "r_editlights_edit command : edit selected light - more documentation below\n"
7374 "r_editlights_remove : remove selected light\n"
7375 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
7376 "r_editlights_importlightentitiesfrommap : reload light entities\n"
7377 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
7379 "origin x y z : set light location\n"
7380 "originx x: set x component of light location\n"
7381 "originy y: set y component of light location\n"
7382 "originz z: set z component of light location\n"
7383 "move x y z : adjust light location\n"
7384 "movex x: adjust x component of light location\n"
7385 "movey y: adjust y component of light location\n"
7386 "movez z: adjust z component of light location\n"
7387 "angles x y z : set light angles\n"
7388 "anglesx x: set x component of light angles\n"
7389 "anglesy y: set y component of light angles\n"
7390 "anglesz z: set z component of light angles\n"
7391 "color r g b : set color of light (can be brighter than 1 1 1)\n"
7392 "radius radius : set radius (size) of light\n"
7393 "colorscale grey : multiply color of light (1 does nothing)\n"
7394 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
7395 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
7396 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
7397 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
7398 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
7399 "cubemap basename : set filter cubemap of light\n"
7400 "shadows 1/0 : turn on/off shadows\n"
7401 "corona n : set corona intensity\n"
7402 "coronasize n : set corona size (0-1)\n"
7403 "ambient n : set ambient intensity (0-1)\n"
7404 "diffuse n : set diffuse intensity (0-1)\n"
7405 "specular n : set specular intensity (0-1)\n"
7406 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
7407 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
7408 "<nothing> : print light properties to console\n"
7412 static void R_Shadow_EditLights_CopyInfo_f(void)
7414 if (!r_editlights.integer)
7416 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
7419 if (!r_shadow_selectedlight)
7421 Con_Print("No selected light.\n");
7424 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
7425 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
7426 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
7427 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
7428 if (r_shadow_selectedlight->cubemapname)
7429 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
7431 r_shadow_bufferlight.cubemapname[0] = 0;
7432 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
7433 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
7434 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
7435 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
7436 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
7437 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
7438 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
7441 static void R_Shadow_EditLights_PasteInfo_f(void)
7443 if (!r_editlights.integer)
7445 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
7448 if (!r_shadow_selectedlight)
7450 Con_Print("No selected light.\n");
7453 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);
7456 static void R_Shadow_EditLights_Lock_f(void)
7458 if (!r_editlights.integer)
7460 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
7463 if (r_editlights_lockcursor)
7465 r_editlights_lockcursor = false;
7468 if (!r_shadow_selectedlight)
7470 Con_Print("No selected light to lock on.\n");
7473 r_editlights_lockcursor = true;
7476 static void R_Shadow_EditLights_Init(void)
7478 Cvar_RegisterVariable(&r_editlights);
7479 Cvar_RegisterVariable(&r_editlights_cursordistance);
7480 Cvar_RegisterVariable(&r_editlights_cursorpushback);
7481 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
7482 Cvar_RegisterVariable(&r_editlights_cursorgrid);
7483 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
7484 Cvar_RegisterVariable(&r_editlights_drawproperties);
7485 Cvar_RegisterVariable(&r_editlights_current_origin);
7486 Cvar_RegisterVariable(&r_editlights_current_angles);
7487 Cvar_RegisterVariable(&r_editlights_current_color);
7488 Cvar_RegisterVariable(&r_editlights_current_radius);
7489 Cvar_RegisterVariable(&r_editlights_current_corona);
7490 Cvar_RegisterVariable(&r_editlights_current_coronasize);
7491 Cvar_RegisterVariable(&r_editlights_current_style);
7492 Cvar_RegisterVariable(&r_editlights_current_shadows);
7493 Cvar_RegisterVariable(&r_editlights_current_cubemap);
7494 Cvar_RegisterVariable(&r_editlights_current_ambient);
7495 Cvar_RegisterVariable(&r_editlights_current_diffuse);
7496 Cvar_RegisterVariable(&r_editlights_current_specular);
7497 Cvar_RegisterVariable(&r_editlights_current_normalmode);
7498 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
7499 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
7500 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
7501 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)");
7502 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
7503 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
7504 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
7505 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)");
7506 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
7507 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
7508 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
7509 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
7510 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
7511 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
7512 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)");
7513 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
7519 =============================================================================
7523 =============================================================================
7526 void R_LightPoint(float *color, const vec3_t p, const int flags)
7528 int i, numlights, flag;
7529 float f, relativepoint[3], dist, dist2, lightradius2;
7534 if (r_fullbright.integer)
7536 VectorSet(color, 1, 1, 1);
7542 if (flags & LP_LIGHTMAP)
7544 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7546 VectorClear(diffuse);
7547 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, color, diffuse, n);
7548 VectorAdd(color, diffuse, color);
7551 VectorSet(color, 1, 1, 1);
7552 color[0] += r_refdef.scene.ambient;
7553 color[1] += r_refdef.scene.ambient;
7554 color[2] += r_refdef.scene.ambient;
7557 if (flags & LP_RTWORLD)
7559 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7560 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7561 for (i = 0; i < numlights; i++)
7563 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7566 light = &dlight->rtlight;
7567 if (!(light->flags & flag))
7570 lightradius2 = light->radius * light->radius;
7571 VectorSubtract(light->shadoworigin, p, relativepoint);
7572 dist2 = VectorLength2(relativepoint);
7573 if (dist2 >= lightradius2)
7575 dist = sqrt(dist2) / light->radius;
7576 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7579 // todo: add to both ambient and diffuse
7580 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)
7581 VectorMA(color, f, light->currentcolor, color);
7584 if (flags & LP_DYNLIGHT)
7587 for (i = 0;i < r_refdef.scene.numlights;i++)
7589 light = r_refdef.scene.lights[i];
7591 lightradius2 = light->radius * light->radius;
7592 VectorSubtract(light->shadoworigin, p, relativepoint);
7593 dist2 = VectorLength2(relativepoint);
7594 if (dist2 >= lightradius2)
7596 dist = sqrt(dist2) / light->radius;
7597 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7600 // todo: add to both ambient and diffuse
7601 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)
7602 VectorMA(color, f, light->color, color);
7607 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
7609 int i, numlights, flag;
7612 float relativepoint[3];
7621 if (r_fullbright.integer)
7623 VectorSet(ambient, 1, 1, 1);
7624 VectorClear(diffuse);
7625 VectorClear(lightdir);
7629 if (flags == LP_LIGHTMAP)
7631 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7632 VectorClear(diffuse);
7633 VectorClear(lightdir);
7634 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7635 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
7637 VectorSet(ambient, 1, 1, 1);
7641 memset(sample, 0, sizeof(sample));
7642 VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7644 if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7647 VectorClear(tempambient);
7649 VectorClear(relativepoint);
7650 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
7651 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
7652 VectorScale(color, r_refdef.lightmapintensity, color);
7653 VectorAdd(sample, tempambient, sample);
7654 VectorMA(sample , 0.5f , color, sample );
7655 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7656 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7657 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7658 // calculate a weighted average light direction as well
7659 intensity = VectorLength(color);
7660 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7663 if (flags & LP_RTWORLD)
7665 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7666 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7667 for (i = 0; i < numlights; i++)
7669 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7672 light = &dlight->rtlight;
7673 if (!(light->flags & flag))
7676 lightradius2 = light->radius * light->radius;
7677 VectorSubtract(light->shadoworigin, p, relativepoint);
7678 dist2 = VectorLength2(relativepoint);
7679 if (dist2 >= lightradius2)
7681 dist = sqrt(dist2) / light->radius;
7682 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
7683 if (intensity <= 0.0f)
7685 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)
7687 // scale down intensity to add to both ambient and diffuse
7688 //intensity *= 0.5f;
7689 VectorNormalize(relativepoint);
7690 VectorScale(light->currentcolor, intensity, color);
7691 VectorMA(sample , 0.5f , color, sample );
7692 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7693 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7694 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7695 // calculate a weighted average light direction as well
7696 intensity *= VectorLength(color);
7697 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7699 // FIXME: sample bouncegrid too!
7702 if (flags & LP_DYNLIGHT)
7705 for (i = 0;i < r_refdef.scene.numlights;i++)
7707 light = r_refdef.scene.lights[i];
7709 lightradius2 = light->radius * light->radius;
7710 VectorSubtract(light->shadoworigin, p, relativepoint);
7711 dist2 = VectorLength2(relativepoint);
7712 if (dist2 >= lightradius2)
7714 dist = sqrt(dist2) / light->radius;
7715 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
7716 if (intensity <= 0.0f)
7718 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)
7720 // scale down intensity to add to both ambient and diffuse
7721 //intensity *= 0.5f;
7722 VectorNormalize(relativepoint);
7723 VectorScale(light->currentcolor, intensity, color);
7724 VectorMA(sample , 0.5f , color, sample );
7725 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7726 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7727 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7728 // calculate a weighted average light direction as well
7729 intensity *= VectorLength(color);
7730 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7734 // calculate the direction we'll use to reduce the sample to a directional light source
7735 VectorCopy(sample + 12, dir);
7736 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
7737 VectorNormalize(dir);
7738 // extract the diffuse color along the chosen direction and scale it
7739 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
7740 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
7741 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
7742 // subtract some of diffuse from ambient
7743 VectorMA(sample, -0.333f, diffuse, ambient);
7744 // store the normalized lightdir
7745 VectorCopy(dir, lightdir);