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, requires gl_fbo 1"};
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", "4096", "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", "1", "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.01", "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_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"};
343 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"};
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_energyperphoton = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_energyperphoton", "10000", "amount of light that one photon should represent"};
346 cvar_t r_shadow_bouncegrid_dynamic_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_lightradiusscale", "10", "particles stop at this fraction of light radius (can be more than 1)"};
347 cvar_t r_shadow_bouncegrid_dynamic_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_maxbounce", "5", "maximum number of bounces for a particle (minimum is 0)"};
348 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"};
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_stablerandom = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_stablerandom", "1", "make particle distribution consistent from frame to frame"};
351 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"};
352 cvar_t r_shadow_bouncegrid_dynamic_x = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_x", "64", "maximum texture size of bouncegrid on X axis"};
353 cvar_t r_shadow_bouncegrid_dynamic_y = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_y", "64", "maximum texture size of bouncegrid on Y axis"};
354 cvar_t r_shadow_bouncegrid_dynamic_z = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_z", "32", "maximum texture size of bouncegrid on Z axis"};
355 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"};
356 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)"};
357 cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
358 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"};
359 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "0.25", "brightness of particles contributing to bouncegrid texture"};
360 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"};
361 cvar_t r_shadow_bouncegrid_lightpathsize = {CVAR_SAVE, "r_shadow_bouncegrid_lightpathsize", "1", "width of the light path for accumulation of light in the bouncegrid texture"};
362 cvar_t r_shadow_bouncegrid_static = {CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
363 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" };
364 cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
365 cvar_t r_shadow_bouncegrid_static_energyperphoton = {CVAR_SAVE, "r_shadow_bouncegrid_static_energyperphoton", "10000", "amount of light that one photon should represent in static mode"};
366 cvar_t r_shadow_bouncegrid_static_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_static_lightradiusscale", "10", "particles stop at this fraction of light radius (can be more than 1) when in static mode"};
367 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"};
368 cvar_t r_shadow_bouncegrid_static_maxphotons = {CVAR_SAVE, "r_shadow_bouncegrid_static_maxphotons", "250000", "upper bound on photons in static mode"};
369 cvar_t r_shadow_bouncegrid_static_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_static_spacing", "64", "unit size of bouncegrid pixel when in static mode"};
370 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
371 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"};
372 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!"};
373 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
374 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
375 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
376 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
377 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
378 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
379 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
380 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
381 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
382 cvar_t r_editlights_drawproperties = {0, "r_editlights_drawproperties", "1", "draw properties of currently selected light"};
383 cvar_t r_editlights_current_origin = {0, "r_editlights_current_origin", "0 0 0", "origin of selected light"};
384 cvar_t r_editlights_current_angles = {0, "r_editlights_current_angles", "0 0 0", "angles of selected light"};
385 cvar_t r_editlights_current_color = {0, "r_editlights_current_color", "1 1 1", "color of selected light"};
386 cvar_t r_editlights_current_radius = {0, "r_editlights_current_radius", "0", "radius of selected light"};
387 cvar_t r_editlights_current_corona = {0, "r_editlights_current_corona", "0", "corona intensity of selected light"};
388 cvar_t r_editlights_current_coronasize = {0, "r_editlights_current_coronasize", "0", "corona size of selected light"};
389 cvar_t r_editlights_current_style = {0, "r_editlights_current_style", "0", "style of selected light"};
390 cvar_t r_editlights_current_shadows = {0, "r_editlights_current_shadows", "0", "shadows flag of selected light"};
391 cvar_t r_editlights_current_cubemap = {0, "r_editlights_current_cubemap", "0", "cubemap of selected light"};
392 cvar_t r_editlights_current_ambient = {0, "r_editlights_current_ambient", "0", "ambient intensity of selected light"};
393 cvar_t r_editlights_current_diffuse = {0, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"};
394 cvar_t r_editlights_current_specular = {0, "r_editlights_current_specular", "1", "specular intensity of selected light"};
395 cvar_t r_editlights_current_normalmode = {0, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"};
396 cvar_t r_editlights_current_realtimemode = {0, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"};
398 r_shadow_bouncegrid_state_t r_shadow_bouncegrid_state;
400 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
401 #define ATTENTABLESIZE 256
402 // 1D gradient, 2D circle and 3D sphere attenuation textures
403 #define ATTEN1DSIZE 32
404 #define ATTEN2DSIZE 64
405 #define ATTEN3DSIZE 32
407 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
408 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
409 static float r_shadow_attentable[ATTENTABLESIZE+1];
411 rtlight_t *r_shadow_compilingrtlight;
412 static memexpandablearray_t r_shadow_worldlightsarray;
413 dlight_t *r_shadow_selectedlight;
414 dlight_t r_shadow_bufferlight;
415 vec3_t r_editlights_cursorlocation;
416 qboolean r_editlights_lockcursor;
418 extern int con_vislines;
420 void R_Shadow_UncompileWorldLights(void);
421 void R_Shadow_ClearWorldLights(void);
422 void R_Shadow_SaveWorldLights(void);
423 void R_Shadow_LoadWorldLights(void);
424 void R_Shadow_LoadLightsFile(void);
425 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
426 void R_Shadow_EditLights_Reload_f(void);
427 void R_Shadow_ValidateCvars(void);
428 static void R_Shadow_MakeTextures(void);
430 #define EDLIGHTSPRSIZE 8
431 skinframe_t *r_editlights_sprcursor;
432 skinframe_t *r_editlights_sprlight;
433 skinframe_t *r_editlights_sprnoshadowlight;
434 skinframe_t *r_editlights_sprcubemaplight;
435 skinframe_t *r_editlights_sprcubemapnoshadowlight;
436 skinframe_t *r_editlights_sprselection;
438 static void R_Shadow_DrawModelShadowMaps(void);
439 static void R_Shadow_MakeShadowMap(int texturesize);
440 static void R_Shadow_MakeVSDCT(void);
441 static void R_Shadow_SetShadowMode(void)
443 r_shadow_shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
444 r_shadow_shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
445 r_shadow_shadowmapmaxsize = bound(r_shadow_shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, r_shadow_shadowmaptexturesize / 8);
446 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
447 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
448 r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
449 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
450 r_shadow_shadowmapsampler = false;
451 r_shadow_shadowmappcf = 0;
452 r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
453 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
454 Mod_AllocLightmap_Init(&r_shadow_shadowmapatlas_state, r_main_mempool, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize);
455 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
457 switch(vid.renderpath)
459 case RENDERPATH_GL20:
460 if(r_shadow_shadowmapfilterquality < 0)
462 if (!r_fb.usedepthtextures)
463 r_shadow_shadowmappcf = 1;
464 else if((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && vid.support.arb_shadow && r_shadow_shadowmapshadowsampler)
466 r_shadow_shadowmapsampler = true;
467 r_shadow_shadowmappcf = 1;
469 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
470 r_shadow_shadowmappcf = 1;
471 else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa"))
472 r_shadow_shadowmappcf = 1;
474 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
478 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
479 switch (r_shadow_shadowmapfilterquality)
484 r_shadow_shadowmappcf = 1;
487 r_shadow_shadowmappcf = 1;
490 r_shadow_shadowmappcf = 2;
494 if (!r_fb.usedepthtextures)
495 r_shadow_shadowmapsampler = false;
496 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
498 case RENDERPATH_D3D9:
499 case RENDERPATH_D3D10:
500 case RENDERPATH_D3D11:
501 case RENDERPATH_SOFT:
502 r_shadow_shadowmapsampler = false;
503 r_shadow_shadowmappcf = 1;
504 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
506 case RENDERPATH_GL11:
507 case RENDERPATH_GL13:
508 case RENDERPATH_GLES1:
509 case RENDERPATH_GLES2:
514 if(R_CompileShader_CheckStaticParms())
518 qboolean R_Shadow_ShadowMappingEnabled(void)
520 switch (r_shadow_shadowmode)
522 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
529 static void R_Shadow_FreeShadowMaps(void)
531 Mod_AllocLightmap_Free(&r_shadow_shadowmapatlas_state);
533 R_Shadow_SetShadowMode();
535 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
539 if (r_shadow_shadowmap2ddepthtexture)
540 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
541 r_shadow_shadowmap2ddepthtexture = NULL;
543 if (r_shadow_shadowmap2ddepthbuffer)
544 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
545 r_shadow_shadowmap2ddepthbuffer = NULL;
547 if (r_shadow_shadowmapvsdcttexture)
548 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
549 r_shadow_shadowmapvsdcttexture = NULL;
552 static void r_shadow_start(void)
554 // allocate vertex processing arrays
555 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
556 r_shadow_attenuationgradienttexture = NULL;
557 r_shadow_attenuation2dtexture = NULL;
558 r_shadow_attenuation3dtexture = NULL;
559 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
560 r_shadow_shadowmap2ddepthtexture = NULL;
561 r_shadow_shadowmap2ddepthbuffer = NULL;
562 r_shadow_shadowmapvsdcttexture = NULL;
563 r_shadow_shadowmapmaxsize = 0;
564 r_shadow_shadowmaptexturesize = 0;
565 r_shadow_shadowmapfilterquality = -1;
566 r_shadow_shadowmapdepthbits = 0;
567 r_shadow_shadowmapvsdct = false;
568 r_shadow_shadowmapsampler = false;
569 r_shadow_shadowmappcf = 0;
572 R_Shadow_FreeShadowMaps();
574 r_shadow_texturepool = NULL;
575 r_shadow_filters_texturepool = NULL;
576 R_Shadow_ValidateCvars();
577 R_Shadow_MakeTextures();
578 r_shadow_scenemaxlights = 0;
579 r_shadow_scenenumlights = 0;
580 r_shadow_scenelightlist = NULL;
581 maxshadowtriangles = 0;
582 shadowelements = NULL;
583 maxshadowvertices = 0;
584 shadowvertex3f = NULL;
592 shadowmarklist = NULL;
597 shadowsideslist = NULL;
598 r_shadow_buffer_numleafpvsbytes = 0;
599 r_shadow_buffer_visitingleafpvs = NULL;
600 r_shadow_buffer_leafpvs = NULL;
601 r_shadow_buffer_leaflist = NULL;
602 r_shadow_buffer_numsurfacepvsbytes = 0;
603 r_shadow_buffer_surfacepvs = NULL;
604 r_shadow_buffer_surfacelist = NULL;
605 r_shadow_buffer_surfacesides = NULL;
606 r_shadow_buffer_numshadowtrispvsbytes = 0;
607 r_shadow_buffer_shadowtrispvs = NULL;
608 r_shadow_buffer_numlighttrispvsbytes = 0;
609 r_shadow_buffer_lighttrispvs = NULL;
611 r_shadow_usingdeferredprepass = false;
612 r_shadow_prepass_width = r_shadow_prepass_height = 0;
614 // determine renderpath specific capabilities, we don't need to figure
615 // these out per frame...
616 switch(vid.renderpath)
618 case RENDERPATH_GL20:
619 r_shadow_bouncegrid_state.allowdirectionalshading = true;
620 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
622 case RENDERPATH_GLES2:
623 // for performance reasons, do not use directional shading on GLES devices
624 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
626 // these renderpaths do not currently have the code to display the bouncegrid, so disable it on them...
627 case RENDERPATH_GL11:
628 case RENDERPATH_GL13:
629 case RENDERPATH_GLES1:
630 case RENDERPATH_SOFT:
631 case RENDERPATH_D3D9:
632 case RENDERPATH_D3D10:
633 case RENDERPATH_D3D11:
638 static void R_Shadow_FreeDeferred(void);
639 static void r_shadow_shutdown(void)
642 R_Shadow_UncompileWorldLights();
644 R_Shadow_FreeShadowMaps();
646 r_shadow_usingdeferredprepass = false;
647 if (r_shadow_prepass_width)
648 R_Shadow_FreeDeferred();
649 r_shadow_prepass_width = r_shadow_prepass_height = 0;
652 r_shadow_scenemaxlights = 0;
653 r_shadow_scenenumlights = 0;
654 if (r_shadow_scenelightlist)
655 Mem_Free(r_shadow_scenelightlist);
656 r_shadow_scenelightlist = NULL;
657 r_shadow_bouncegrid_state.highpixels = NULL;
658 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
659 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
660 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
661 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
662 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
663 r_shadow_bouncegrid_state.maxsplatpaths = 0;
664 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
665 r_shadow_attenuationgradienttexture = NULL;
666 r_shadow_attenuation2dtexture = NULL;
667 r_shadow_attenuation3dtexture = NULL;
668 R_FreeTexturePool(&r_shadow_texturepool);
669 R_FreeTexturePool(&r_shadow_filters_texturepool);
670 maxshadowtriangles = 0;
672 Mem_Free(shadowelements);
673 shadowelements = NULL;
675 Mem_Free(shadowvertex3f);
676 shadowvertex3f = NULL;
679 Mem_Free(vertexupdate);
682 Mem_Free(vertexremap);
688 Mem_Free(shadowmark);
691 Mem_Free(shadowmarklist);
692 shadowmarklist = NULL;
697 Mem_Free(shadowsides);
700 Mem_Free(shadowsideslist);
701 shadowsideslist = NULL;
702 r_shadow_buffer_numleafpvsbytes = 0;
703 if (r_shadow_buffer_visitingleafpvs)
704 Mem_Free(r_shadow_buffer_visitingleafpvs);
705 r_shadow_buffer_visitingleafpvs = NULL;
706 if (r_shadow_buffer_leafpvs)
707 Mem_Free(r_shadow_buffer_leafpvs);
708 r_shadow_buffer_leafpvs = NULL;
709 if (r_shadow_buffer_leaflist)
710 Mem_Free(r_shadow_buffer_leaflist);
711 r_shadow_buffer_leaflist = NULL;
712 r_shadow_buffer_numsurfacepvsbytes = 0;
713 if (r_shadow_buffer_surfacepvs)
714 Mem_Free(r_shadow_buffer_surfacepvs);
715 r_shadow_buffer_surfacepvs = NULL;
716 if (r_shadow_buffer_surfacelist)
717 Mem_Free(r_shadow_buffer_surfacelist);
718 r_shadow_buffer_surfacelist = NULL;
719 if (r_shadow_buffer_surfacesides)
720 Mem_Free(r_shadow_buffer_surfacesides);
721 r_shadow_buffer_surfacesides = NULL;
722 r_shadow_buffer_numshadowtrispvsbytes = 0;
723 if (r_shadow_buffer_shadowtrispvs)
724 Mem_Free(r_shadow_buffer_shadowtrispvs);
725 r_shadow_buffer_numlighttrispvsbytes = 0;
726 if (r_shadow_buffer_lighttrispvs)
727 Mem_Free(r_shadow_buffer_lighttrispvs);
730 static void r_shadow_newmap(void)
732 r_shadow_bouncegrid_state.highpixels = NULL;
733 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
734 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
735 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
736 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
737 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
738 r_shadow_bouncegrid_state.maxsplatpaths = 0;
739 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
740 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
741 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
742 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
743 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
744 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
745 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
746 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
747 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
748 R_Shadow_EditLights_Reload_f();
751 void R_Shadow_Init(void)
753 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
754 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
755 Cvar_RegisterVariable(&r_shadow_usebihculling);
756 Cvar_RegisterVariable(&r_shadow_usenormalmap);
757 Cvar_RegisterVariable(&r_shadow_debuglight);
758 Cvar_RegisterVariable(&r_shadow_deferred);
759 Cvar_RegisterVariable(&r_shadow_gloss);
760 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
761 Cvar_RegisterVariable(&r_shadow_glossintensity);
762 Cvar_RegisterVariable(&r_shadow_glossexponent);
763 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
764 Cvar_RegisterVariable(&r_shadow_glossexact);
765 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
766 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
767 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
768 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
769 Cvar_RegisterVariable(&r_shadow_projectdistance);
770 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
771 Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
772 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
773 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
774 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
775 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
776 Cvar_RegisterVariable(&r_shadow_realtime_world);
777 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
778 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
779 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
780 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
781 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
782 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
783 Cvar_RegisterVariable(&r_shadow_scissor);
784 Cvar_RegisterVariable(&r_shadow_shadowmapping);
785 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
786 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
787 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
788 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
789 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
790 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
791 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
792 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturesize);
793 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
794 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
795 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
796 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
797 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
798 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
799 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
800 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
801 Cvar_RegisterVariable(&r_shadow_polygonfactor);
802 Cvar_RegisterVariable(&r_shadow_polygonoffset);
803 Cvar_RegisterVariable(&r_shadow_texture3d);
804 Cvar_RegisterVariable(&r_shadow_bouncegrid);
805 Cvar_RegisterVariable(&r_shadow_bouncegrid_blur);
806 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
807 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_bounceminimumintensity);
808 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_culllightpaths);
809 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_directionalshading);
810 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_dlightparticlemultiplier);
811 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_hitmodels);
812 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_energyperphoton);
813 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_lightradiusscale);
814 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxbounce);
815 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxphotons);
816 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_spacing);
817 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_stablerandom);
818 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_updateinterval);
819 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_x);
820 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_y);
821 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_z);
822 Cvar_RegisterVariable(&r_shadow_bouncegrid_floatcolors);
823 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
824 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
825 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize);
826 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
827 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
828 Cvar_RegisterVariable(&r_shadow_bouncegrid_sortlightpaths);
829 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
830 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_bounceminimumintensity);
831 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
832 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_energyperphoton);
833 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
834 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
835 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxphotons);
836 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_spacing);
837 Cvar_RegisterVariable(&r_coronas);
838 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
839 Cvar_RegisterVariable(&r_coronas_occlusionquery);
840 Cvar_RegisterVariable(&gl_flashblend);
841 Cvar_RegisterVariable(&gl_ext_separatestencil);
842 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
843 R_Shadow_EditLights_Init();
844 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
845 r_shadow_scenemaxlights = 0;
846 r_shadow_scenenumlights = 0;
847 r_shadow_scenelightlist = NULL;
848 maxshadowtriangles = 0;
849 shadowelements = NULL;
850 maxshadowvertices = 0;
851 shadowvertex3f = NULL;
859 shadowmarklist = NULL;
864 shadowsideslist = NULL;
865 r_shadow_buffer_numleafpvsbytes = 0;
866 r_shadow_buffer_visitingleafpvs = NULL;
867 r_shadow_buffer_leafpvs = NULL;
868 r_shadow_buffer_leaflist = NULL;
869 r_shadow_buffer_numsurfacepvsbytes = 0;
870 r_shadow_buffer_surfacepvs = NULL;
871 r_shadow_buffer_surfacelist = NULL;
872 r_shadow_buffer_surfacesides = NULL;
873 r_shadow_buffer_shadowtrispvs = NULL;
874 r_shadow_buffer_lighttrispvs = NULL;
875 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
878 matrix4x4_t matrix_attenuationxyz =
881 {0.5, 0.0, 0.0, 0.5},
882 {0.0, 0.5, 0.0, 0.5},
883 {0.0, 0.0, 0.5, 0.5},
888 matrix4x4_t matrix_attenuationz =
891 {0.0, 0.0, 0.5, 0.5},
892 {0.0, 0.0, 0.0, 0.5},
893 {0.0, 0.0, 0.0, 0.5},
898 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
900 numvertices = ((numvertices + 255) & ~255) * vertscale;
901 numtriangles = ((numtriangles + 255) & ~255) * triscale;
902 // make sure shadowelements is big enough for this volume
903 if (maxshadowtriangles < numtriangles)
905 maxshadowtriangles = numtriangles;
907 Mem_Free(shadowelements);
908 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
910 // make sure shadowvertex3f is big enough for this volume
911 if (maxshadowvertices < numvertices)
913 maxshadowvertices = numvertices;
915 Mem_Free(shadowvertex3f);
916 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
920 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
922 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
923 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
924 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
925 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
926 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
928 if (r_shadow_buffer_visitingleafpvs)
929 Mem_Free(r_shadow_buffer_visitingleafpvs);
930 if (r_shadow_buffer_leafpvs)
931 Mem_Free(r_shadow_buffer_leafpvs);
932 if (r_shadow_buffer_leaflist)
933 Mem_Free(r_shadow_buffer_leaflist);
934 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
935 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
936 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
937 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
939 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
941 if (r_shadow_buffer_surfacepvs)
942 Mem_Free(r_shadow_buffer_surfacepvs);
943 if (r_shadow_buffer_surfacelist)
944 Mem_Free(r_shadow_buffer_surfacelist);
945 if (r_shadow_buffer_surfacesides)
946 Mem_Free(r_shadow_buffer_surfacesides);
947 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
948 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
949 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
950 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
952 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
954 if (r_shadow_buffer_shadowtrispvs)
955 Mem_Free(r_shadow_buffer_shadowtrispvs);
956 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
957 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
959 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
961 if (r_shadow_buffer_lighttrispvs)
962 Mem_Free(r_shadow_buffer_lighttrispvs);
963 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
964 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
968 void R_Shadow_PrepareShadowMark(int numtris)
970 // make sure shadowmark is big enough for this volume
971 if (maxshadowmark < numtris)
973 maxshadowmark = numtris;
975 Mem_Free(shadowmark);
977 Mem_Free(shadowmarklist);
978 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
979 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
983 // if shadowmarkcount wrapped we clear the array and adjust accordingly
984 if (shadowmarkcount == 0)
987 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
992 void R_Shadow_PrepareShadowSides(int numtris)
994 if (maxshadowsides < numtris)
996 maxshadowsides = numtris;
998 Mem_Free(shadowsides);
1000 Mem_Free(shadowsideslist);
1001 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
1002 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
1007 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)
1010 int outtriangles = 0, outvertices = 0;
1012 const float *vertex;
1013 float ratio, direction[3], projectvector[3];
1015 if (projectdirection)
1016 VectorScale(projectdirection, projectdistance, projectvector);
1018 VectorClear(projectvector);
1020 // create the vertices
1021 if (projectdirection)
1023 for (i = 0;i < numshadowmarktris;i++)
1025 element = inelement3i + shadowmarktris[i] * 3;
1026 for (j = 0;j < 3;j++)
1028 if (vertexupdate[element[j]] != vertexupdatenum)
1030 vertexupdate[element[j]] = vertexupdatenum;
1031 vertexremap[element[j]] = outvertices;
1032 vertex = invertex3f + element[j] * 3;
1033 // project one copy of the vertex according to projectvector
1034 VectorCopy(vertex, outvertex3f);
1035 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1044 for (i = 0;i < numshadowmarktris;i++)
1046 element = inelement3i + shadowmarktris[i] * 3;
1047 for (j = 0;j < 3;j++)
1049 if (vertexupdate[element[j]] != vertexupdatenum)
1051 vertexupdate[element[j]] = vertexupdatenum;
1052 vertexremap[element[j]] = outvertices;
1053 vertex = invertex3f + element[j] * 3;
1054 // project one copy of the vertex to the sphere radius of the light
1055 // (FIXME: would projecting it to the light box be better?)
1056 VectorSubtract(vertex, projectorigin, direction);
1057 ratio = projectdistance / VectorLength(direction);
1058 VectorCopy(vertex, outvertex3f);
1059 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1067 if (r_shadow_frontsidecasting.integer)
1069 for (i = 0;i < numshadowmarktris;i++)
1071 int remappedelement[3];
1073 const int *neighbortriangle;
1075 markindex = shadowmarktris[i] * 3;
1076 element = inelement3i + markindex;
1077 neighbortriangle = inneighbor3i + markindex;
1078 // output the front and back triangles
1079 outelement3i[0] = vertexremap[element[0]];
1080 outelement3i[1] = vertexremap[element[1]];
1081 outelement3i[2] = vertexremap[element[2]];
1082 outelement3i[3] = vertexremap[element[2]] + 1;
1083 outelement3i[4] = vertexremap[element[1]] + 1;
1084 outelement3i[5] = vertexremap[element[0]] + 1;
1088 // output the sides (facing outward from this triangle)
1089 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1091 remappedelement[0] = vertexremap[element[0]];
1092 remappedelement[1] = vertexremap[element[1]];
1093 outelement3i[0] = remappedelement[1];
1094 outelement3i[1] = remappedelement[0];
1095 outelement3i[2] = remappedelement[0] + 1;
1096 outelement3i[3] = remappedelement[1];
1097 outelement3i[4] = remappedelement[0] + 1;
1098 outelement3i[5] = remappedelement[1] + 1;
1103 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1105 remappedelement[1] = vertexremap[element[1]];
1106 remappedelement[2] = vertexremap[element[2]];
1107 outelement3i[0] = remappedelement[2];
1108 outelement3i[1] = remappedelement[1];
1109 outelement3i[2] = remappedelement[1] + 1;
1110 outelement3i[3] = remappedelement[2];
1111 outelement3i[4] = remappedelement[1] + 1;
1112 outelement3i[5] = remappedelement[2] + 1;
1117 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1119 remappedelement[0] = vertexremap[element[0]];
1120 remappedelement[2] = vertexremap[element[2]];
1121 outelement3i[0] = remappedelement[0];
1122 outelement3i[1] = remappedelement[2];
1123 outelement3i[2] = remappedelement[2] + 1;
1124 outelement3i[3] = remappedelement[0];
1125 outelement3i[4] = remappedelement[2] + 1;
1126 outelement3i[5] = remappedelement[0] + 1;
1135 for (i = 0;i < numshadowmarktris;i++)
1137 int remappedelement[3];
1139 const int *neighbortriangle;
1141 markindex = shadowmarktris[i] * 3;
1142 element = inelement3i + markindex;
1143 neighbortriangle = inneighbor3i + markindex;
1144 // output the front and back triangles
1145 outelement3i[0] = vertexremap[element[2]];
1146 outelement3i[1] = vertexremap[element[1]];
1147 outelement3i[2] = vertexremap[element[0]];
1148 outelement3i[3] = vertexremap[element[0]] + 1;
1149 outelement3i[4] = vertexremap[element[1]] + 1;
1150 outelement3i[5] = vertexremap[element[2]] + 1;
1154 // output the sides (facing outward from this triangle)
1155 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1157 remappedelement[0] = vertexremap[element[0]];
1158 remappedelement[1] = vertexremap[element[1]];
1159 outelement3i[0] = remappedelement[0];
1160 outelement3i[1] = remappedelement[1];
1161 outelement3i[2] = remappedelement[1] + 1;
1162 outelement3i[3] = remappedelement[0];
1163 outelement3i[4] = remappedelement[1] + 1;
1164 outelement3i[5] = remappedelement[0] + 1;
1169 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1171 remappedelement[1] = vertexremap[element[1]];
1172 remappedelement[2] = vertexremap[element[2]];
1173 outelement3i[0] = remappedelement[1];
1174 outelement3i[1] = remappedelement[2];
1175 outelement3i[2] = remappedelement[2] + 1;
1176 outelement3i[3] = remappedelement[1];
1177 outelement3i[4] = remappedelement[2] + 1;
1178 outelement3i[5] = remappedelement[1] + 1;
1183 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1185 remappedelement[0] = vertexremap[element[0]];
1186 remappedelement[2] = vertexremap[element[2]];
1187 outelement3i[0] = remappedelement[2];
1188 outelement3i[1] = remappedelement[0];
1189 outelement3i[2] = remappedelement[0] + 1;
1190 outelement3i[3] = remappedelement[2];
1191 outelement3i[4] = remappedelement[0] + 1;
1192 outelement3i[5] = remappedelement[2] + 1;
1200 *outnumvertices = outvertices;
1201 return outtriangles;
1204 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)
1207 int outtriangles = 0, outvertices = 0;
1209 const float *vertex;
1210 float ratio, direction[3], projectvector[3];
1213 if (projectdirection)
1214 VectorScale(projectdirection, projectdistance, projectvector);
1216 VectorClear(projectvector);
1218 for (i = 0;i < numshadowmarktris;i++)
1220 int remappedelement[3];
1222 const int *neighbortriangle;
1224 markindex = shadowmarktris[i] * 3;
1225 neighbortriangle = inneighbor3i + markindex;
1226 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1227 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1228 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1229 if (side[0] + side[1] + side[2] == 0)
1233 element = inelement3i + markindex;
1235 // create the vertices
1236 for (j = 0;j < 3;j++)
1238 if (side[j] + side[j+1] == 0)
1241 if (vertexupdate[k] != vertexupdatenum)
1243 vertexupdate[k] = vertexupdatenum;
1244 vertexremap[k] = outvertices;
1245 vertex = invertex3f + k * 3;
1246 VectorCopy(vertex, outvertex3f);
1247 if (projectdirection)
1249 // project one copy of the vertex according to projectvector
1250 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1254 // project one copy of the vertex to the sphere radius of the light
1255 // (FIXME: would projecting it to the light box be better?)
1256 VectorSubtract(vertex, projectorigin, direction);
1257 ratio = projectdistance / VectorLength(direction);
1258 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1265 // output the sides (facing outward from this triangle)
1268 remappedelement[0] = vertexremap[element[0]];
1269 remappedelement[1] = vertexremap[element[1]];
1270 outelement3i[0] = remappedelement[1];
1271 outelement3i[1] = remappedelement[0];
1272 outelement3i[2] = remappedelement[0] + 1;
1273 outelement3i[3] = remappedelement[1];
1274 outelement3i[4] = remappedelement[0] + 1;
1275 outelement3i[5] = remappedelement[1] + 1;
1282 remappedelement[1] = vertexremap[element[1]];
1283 remappedelement[2] = vertexremap[element[2]];
1284 outelement3i[0] = remappedelement[2];
1285 outelement3i[1] = remappedelement[1];
1286 outelement3i[2] = remappedelement[1] + 1;
1287 outelement3i[3] = remappedelement[2];
1288 outelement3i[4] = remappedelement[1] + 1;
1289 outelement3i[5] = remappedelement[2] + 1;
1296 remappedelement[0] = vertexremap[element[0]];
1297 remappedelement[2] = vertexremap[element[2]];
1298 outelement3i[0] = remappedelement[0];
1299 outelement3i[1] = remappedelement[2];
1300 outelement3i[2] = remappedelement[2] + 1;
1301 outelement3i[3] = remappedelement[0];
1302 outelement3i[4] = remappedelement[2] + 1;
1303 outelement3i[5] = remappedelement[0] + 1;
1310 *outnumvertices = outvertices;
1311 return outtriangles;
1314 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)
1320 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1322 tend = firsttriangle + numtris;
1323 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1325 // surface box entirely inside light box, no box cull
1326 if (projectdirection)
1328 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1330 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1331 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1332 shadowmarklist[numshadowmark++] = t;
1337 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1338 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1339 shadowmarklist[numshadowmark++] = t;
1344 // surface box not entirely inside light box, cull each triangle
1345 if (projectdirection)
1347 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1349 v[0] = invertex3f + e[0] * 3;
1350 v[1] = invertex3f + e[1] * 3;
1351 v[2] = invertex3f + e[2] * 3;
1352 TriangleNormal(v[0], v[1], v[2], normal);
1353 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1354 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1355 shadowmarklist[numshadowmark++] = t;
1360 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1362 v[0] = invertex3f + e[0] * 3;
1363 v[1] = invertex3f + e[1] * 3;
1364 v[2] = invertex3f + e[2] * 3;
1365 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1366 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1367 shadowmarklist[numshadowmark++] = t;
1373 static qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1378 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1380 // check if the shadow volume intersects the near plane
1382 // a ray between the eye and light origin may intersect the caster,
1383 // indicating that the shadow may touch the eye location, however we must
1384 // test the near plane (a polygon), not merely the eye location, so it is
1385 // easiest to enlarge the caster bounding shape slightly for this.
1391 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)
1393 int i, tris, outverts;
1394 if (projectdistance < 0.1)
1396 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1399 if (!numverts || !nummarktris)
1401 // make sure shadowelements is big enough for this volume
1402 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1403 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1405 if (maxvertexupdate < numverts)
1407 maxvertexupdate = numverts;
1409 Mem_Free(vertexupdate);
1411 Mem_Free(vertexremap);
1412 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1413 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1414 vertexupdatenum = 0;
1417 if (vertexupdatenum == 0)
1419 vertexupdatenum = 1;
1420 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1421 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1424 for (i = 0;i < nummarktris;i++)
1425 shadowmark[marktris[i]] = shadowmarkcount;
1427 if (r_shadow_compilingrtlight)
1429 // if we're compiling an rtlight, capture the mesh
1430 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1431 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1432 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1433 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1435 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1437 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1438 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1439 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1443 // decide which type of shadow to generate and set stencil mode
1444 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1445 // generate the sides or a solid volume, depending on type
1446 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1447 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1449 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1450 r_refdef.stats[r_stat_lights_dynamicshadowtriangles] += tris;
1451 r_refdef.stats[r_stat_lights_shadowtriangles] += tris;
1452 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1454 // increment stencil if frontface is infront of depthbuffer
1455 GL_CullFace(r_refdef.view.cullface_front);
1456 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1457 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1458 // decrement stencil if backface is infront of depthbuffer
1459 GL_CullFace(r_refdef.view.cullface_back);
1460 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1462 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1464 // decrement stencil if backface is behind depthbuffer
1465 GL_CullFace(r_refdef.view.cullface_front);
1466 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1467 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1468 // increment stencil if frontface is behind depthbuffer
1469 GL_CullFace(r_refdef.view.cullface_back);
1470 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1472 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1473 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1477 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1479 // p1, p2, p3 are in the cubemap's local coordinate system
1480 // bias = border/(size - border)
1483 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1484 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1485 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1486 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1488 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1489 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1490 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1491 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1493 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1494 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1495 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1497 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1498 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1499 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1500 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1502 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1503 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1504 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1505 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1507 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1508 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1509 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1511 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1512 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1513 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1514 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1516 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1517 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1518 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1519 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1521 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1522 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1523 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1528 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1530 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1531 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1534 VectorSubtract(maxs, mins, radius);
1535 VectorScale(radius, 0.5f, radius);
1536 VectorAdd(mins, radius, center);
1537 Matrix4x4_Transform(worldtolight, center, lightcenter);
1538 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1539 VectorSubtract(lightcenter, lightradius, pmin);
1540 VectorAdd(lightcenter, lightradius, pmax);
1542 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1543 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1544 if(ap1 > bias*an1 && ap2 > bias*an2)
1546 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1547 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1548 if(an1 > bias*ap1 && an2 > bias*ap2)
1550 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1551 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1553 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1554 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1555 if(ap1 > bias*an1 && ap2 > bias*an2)
1557 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1558 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1559 if(an1 > bias*ap1 && an2 > bias*ap2)
1561 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1562 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1564 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1565 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1566 if(ap1 > bias*an1 && ap2 > bias*an2)
1568 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1569 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1570 if(an1 > bias*ap1 && an2 > bias*ap2)
1572 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1573 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1578 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1580 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1582 // p is in the cubemap's local coordinate system
1583 // bias = border/(size - border)
1584 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1585 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1586 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1588 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1589 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1590 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1591 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1592 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1593 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1597 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1601 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1602 float scale = (size - 2*border)/size, len;
1603 float bias = border / (float)(size - border), dp, dn, ap, an;
1604 // check if cone enclosing side would cross frustum plane
1605 scale = 2 / (scale*scale + 2);
1606 Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
1607 for (i = 0;i < 5;i++)
1609 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
1611 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1612 len = scale*VectorLength2(n);
1613 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1614 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1615 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1617 if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1619 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1620 len = scale*VectorLength2(n);
1621 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1622 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1623 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1625 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1626 // check if frustum corners/origin cross plane sides
1628 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1629 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1630 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1631 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1632 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1633 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1634 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1635 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1636 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1637 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1638 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1639 for (i = 0;i < 4;i++)
1641 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1642 VectorSubtract(n, p, n);
1643 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1644 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1645 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1646 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1647 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1648 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1649 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1650 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1651 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1654 // finite version, assumes corners are a finite distance from origin dependent on far plane
1655 for (i = 0;i < 5;i++)
1657 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1658 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1659 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1660 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1661 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1662 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1663 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1664 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1665 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1666 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1669 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1672 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)
1680 int mask, surfacemask = 0;
1681 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1683 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1684 tend = firsttriangle + numtris;
1685 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1687 // surface box entirely inside light box, no box cull
1688 if (projectdirection)
1690 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1692 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1693 TriangleNormal(v[0], v[1], v[2], normal);
1694 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1696 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1697 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1698 surfacemask |= mask;
1701 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;
1702 shadowsides[numshadowsides] = mask;
1703 shadowsideslist[numshadowsides++] = t;
1710 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1712 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1713 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1715 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1716 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1717 surfacemask |= mask;
1720 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;
1721 shadowsides[numshadowsides] = mask;
1722 shadowsideslist[numshadowsides++] = t;
1730 // surface box not entirely inside light box, cull each triangle
1731 if (projectdirection)
1733 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1735 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1736 TriangleNormal(v[0], v[1], v[2], normal);
1737 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1738 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1740 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1741 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1742 surfacemask |= mask;
1745 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;
1746 shadowsides[numshadowsides] = mask;
1747 shadowsideslist[numshadowsides++] = t;
1754 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1756 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1757 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1758 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1760 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1761 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1762 surfacemask |= mask;
1765 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;
1766 shadowsides[numshadowsides] = mask;
1767 shadowsideslist[numshadowsides++] = t;
1776 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)
1778 int i, j, outtriangles = 0;
1779 int *outelement3i[6];
1780 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1782 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1783 // make sure shadowelements is big enough for this mesh
1784 if (maxshadowtriangles < outtriangles)
1785 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1787 // compute the offset and size of the separate index lists for each cubemap side
1789 for (i = 0;i < 6;i++)
1791 outelement3i[i] = shadowelements + outtriangles * 3;
1792 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1793 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1794 outtriangles += sidetotals[i];
1797 // gather up the (sparse) triangles into separate index lists for each cubemap side
1798 for (i = 0;i < numsidetris;i++)
1800 const int *element = elements + sidetris[i] * 3;
1801 for (j = 0;j < 6;j++)
1803 if (sides[i] & (1 << j))
1805 outelement3i[j][0] = element[0];
1806 outelement3i[j][1] = element[1];
1807 outelement3i[j][2] = element[2];
1808 outelement3i[j] += 3;
1813 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1816 static void R_Shadow_MakeTextures_MakeCorona(void)
1820 unsigned char pixels[32][32][4];
1821 for (y = 0;y < 32;y++)
1823 dy = (y - 15.5f) * (1.0f / 16.0f);
1824 for (x = 0;x < 32;x++)
1826 dx = (x - 15.5f) * (1.0f / 16.0f);
1827 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1828 a = bound(0, a, 255);
1829 pixels[y][x][0] = a;
1830 pixels[y][x][1] = a;
1831 pixels[y][x][2] = a;
1832 pixels[y][x][3] = 255;
1835 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, false);
1838 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1840 float dist = sqrt(x*x+y*y+z*z);
1841 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1842 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1843 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1846 static void R_Shadow_MakeTextures(void)
1849 float intensity, dist;
1851 R_Shadow_FreeShadowMaps();
1852 R_FreeTexturePool(&r_shadow_texturepool);
1853 r_shadow_texturepool = R_AllocTexturePool();
1854 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1855 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1856 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1857 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1858 for (x = 0;x <= ATTENTABLESIZE;x++)
1860 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1861 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1862 r_shadow_attentable[x] = bound(0, intensity, 1);
1864 // 1D gradient texture
1865 for (x = 0;x < ATTEN1DSIZE;x++)
1866 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1867 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1868 // 2D circle texture
1869 for (y = 0;y < ATTEN2DSIZE;y++)
1870 for (x = 0;x < ATTEN2DSIZE;x++)
1871 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);
1872 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1873 // 3D sphere texture
1874 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1876 for (z = 0;z < ATTEN3DSIZE;z++)
1877 for (y = 0;y < ATTEN3DSIZE;y++)
1878 for (x = 0;x < ATTEN3DSIZE;x++)
1879 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));
1880 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);
1883 r_shadow_attenuation3dtexture = NULL;
1886 R_Shadow_MakeTextures_MakeCorona();
1888 // Editor light sprites
1889 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1906 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1907 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1924 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1925 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1942 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1943 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1960 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1961 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1978 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1979 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1996 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1999 void R_Shadow_ValidateCvars(void)
2001 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
2002 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
2003 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
2004 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
2005 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
2006 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
2009 void R_Shadow_RenderMode_Begin(void)
2015 R_Shadow_ValidateCvars();
2017 if (!r_shadow_attenuation2dtexture
2018 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
2019 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
2020 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
2021 R_Shadow_MakeTextures();
2024 R_Mesh_ResetTextureState();
2025 GL_BlendFunc(GL_ONE, GL_ZERO);
2026 GL_DepthRange(0, 1);
2027 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
2029 GL_DepthMask(false);
2030 GL_Color(0, 0, 0, 1);
2031 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2033 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2035 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
2037 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
2038 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
2040 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
2042 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
2043 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
2047 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
2048 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
2051 switch(vid.renderpath)
2053 case RENDERPATH_GL20:
2054 case RENDERPATH_D3D9:
2055 case RENDERPATH_D3D10:
2056 case RENDERPATH_D3D11:
2057 case RENDERPATH_SOFT:
2058 case RENDERPATH_GLES2:
2059 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
2061 case RENDERPATH_GL11:
2062 case RENDERPATH_GL13:
2063 case RENDERPATH_GLES1:
2064 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
2065 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
2066 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
2067 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
2068 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
2069 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
2071 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
2077 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
2078 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
2079 r_shadow_drawbuffer = drawbuffer;
2080 r_shadow_readbuffer = readbuffer;
2082 r_shadow_cullface_front = r_refdef.view.cullface_front;
2083 r_shadow_cullface_back = r_refdef.view.cullface_back;
2086 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
2088 rsurface.rtlight = rtlight;
2091 void R_Shadow_RenderMode_Reset(void)
2093 R_Mesh_ResetTextureState();
2094 R_Mesh_SetRenderTargets(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture, NULL, NULL, NULL);
2095 R_SetViewport(&r_refdef.view.viewport);
2096 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
2097 GL_DepthRange(0, 1);
2099 GL_DepthMask(false);
2100 GL_DepthFunc(GL_LEQUAL);
2101 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2102 r_refdef.view.cullface_front = r_shadow_cullface_front;
2103 r_refdef.view.cullface_back = r_shadow_cullface_back;
2104 GL_CullFace(r_refdef.view.cullface_back);
2105 GL_Color(1, 1, 1, 1);
2106 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2107 GL_BlendFunc(GL_ONE, GL_ZERO);
2108 R_SetupShader_Generic_NoTexture(false, false);
2109 r_shadow_usingshadowmap2d = false;
2110 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2113 void R_Shadow_ClearStencil(void)
2115 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2116 r_refdef.stats[r_stat_lights_clears]++;
2119 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2121 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2122 if (r_shadow_rendermode == mode)
2124 R_Shadow_RenderMode_Reset();
2125 GL_DepthFunc(GL_LESS);
2126 GL_ColorMask(0, 0, 0, 0);
2127 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2128 GL_CullFace(GL_NONE);
2129 R_SetupShader_DepthOrShadow(false, false, false); // FIXME test if we have a skeletal model?
2130 r_shadow_rendermode = mode;
2135 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2136 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2137 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2139 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2140 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2141 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2146 static void R_Shadow_MakeVSDCT(void)
2148 // maps to a 2x3 texture rectangle with normalized coordinates
2153 // stores abs(dir.xy), offset.xy/2.5
2154 unsigned char data[4*6] =
2156 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2157 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2158 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2159 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2160 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2161 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2163 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2166 static void R_Shadow_MakeShadowMap(int texturesize)
2168 switch (r_shadow_shadowmode)
2170 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2171 if (r_shadow_shadowmap2ddepthtexture) return;
2172 if (r_fb.usedepthtextures)
2174 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);
2175 r_shadow_shadowmap2ddepthbuffer = NULL;
2176 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2180 r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", texturesize, texturesize, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2181 r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
2182 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2190 void R_Shadow_ClearShadowMapTexture(void)
2192 r_viewport_t viewport;
2193 float clearcolor[4];
2195 // if they don't exist, create our textures now
2196 if (!r_shadow_shadowmap2ddepthtexture)
2197 R_Shadow_MakeShadowMap(r_shadow_shadowmaptexturesize);
2198 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2199 R_Shadow_MakeVSDCT();
2201 // we're setting up to render shadowmaps, so change rendermode
2202 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2204 R_Mesh_ResetTextureState();
2205 R_Shadow_RenderMode_Reset();
2206 if (r_shadow_shadowmap2ddepthbuffer)
2207 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2209 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2210 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2211 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2215 // we have to set a viewport to clear anything in some renderpaths (D3D)
2216 R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize, 0, 0, 1.0, 1.0, 0.001f, 1.0f, NULL);
2217 R_SetViewport(&viewport);
2218 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2219 if (r_shadow_shadowmap2ddepthbuffer)
2220 GL_ColorMask(1, 1, 1, 1);
2222 GL_ColorMask(0, 0, 0, 0);
2223 switch (vid.renderpath)
2225 case RENDERPATH_GL11:
2226 case RENDERPATH_GL13:
2227 case RENDERPATH_GL20:
2228 case RENDERPATH_SOFT:
2229 case RENDERPATH_GLES1:
2230 case RENDERPATH_GLES2:
2231 GL_CullFace(r_refdef.view.cullface_back);
2233 case RENDERPATH_D3D9:
2234 case RENDERPATH_D3D10:
2235 case RENDERPATH_D3D11:
2236 // we invert the cull mode because we flip the projection matrix
2237 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2238 GL_CullFace(r_refdef.view.cullface_front);
2241 Vector4Set(clearcolor, 1, 1, 1, 1);
2242 if (r_shadow_shadowmap2ddepthbuffer)
2243 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2245 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2248 static void R_Shadow_SetShadowmapParametersForLight(qboolean noselfshadowpass)
2250 int size = rsurface.rtlight->shadowmapatlassidesize;
2251 float nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2252 float farclip = 1.0f;
2253 float bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2254 r_shadow_lightshadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
2255 r_shadow_lightshadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
2256 r_shadow_lightshadowmap_texturescale[2] = rsurface.rtlight->shadowmapatlasposition[0] + (noselfshadowpass ? size * 2 : 0);
2257 r_shadow_lightshadowmap_texturescale[3] = rsurface.rtlight->shadowmapatlasposition[1];
2258 r_shadow_lightshadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2259 r_shadow_lightshadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2260 r_shadow_lightshadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2261 r_shadow_lightshadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2262 if (r_shadow_shadowmap2ddepthbuffer)
2264 // completely different meaning than in depthtexture approach
2265 r_shadow_lightshadowmap_parameters[1] = 0;
2266 r_shadow_lightshadowmap_parameters[3] = -bias;
2270 static void R_Shadow_RenderMode_ShadowMap(int side, int size, int x, int y)
2272 float nearclip, farclip, bias;
2273 r_viewport_t viewport;
2275 float clearcolor[4];
2277 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_SHADOWMAP2D)
2279 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2281 R_Mesh_ResetTextureState();
2282 R_Shadow_RenderMode_Reset();
2283 if (r_shadow_shadowmap2ddepthbuffer)
2284 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2286 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2287 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2288 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2293 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2295 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2297 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
2298 R_SetViewport(&viewport);
2299 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2300 flipped = (side & 1) ^ (side >> 2);
2301 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2302 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2304 Vector4Set(clearcolor, 1,1,1,1);
2305 if (r_shadow_shadowmap2ddepthbuffer)
2306 GL_ColorMask(1,1,1,1);
2308 GL_ColorMask(0,0,0,0);
2309 switch(vid.renderpath)
2311 case RENDERPATH_GL11:
2312 case RENDERPATH_GL13:
2313 case RENDERPATH_GL20:
2314 case RENDERPATH_SOFT:
2315 case RENDERPATH_GLES1:
2316 case RENDERPATH_GLES2:
2317 GL_CullFace(r_refdef.view.cullface_back);
2319 case RENDERPATH_D3D9:
2320 case RENDERPATH_D3D10:
2321 case RENDERPATH_D3D11:
2322 // we invert the cull mode because we flip the projection matrix
2323 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2324 GL_CullFace(r_refdef.view.cullface_front);
2328 // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
2329 r_shadow_shadowmapside = side;
2332 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass)
2334 R_Mesh_ResetTextureState();
2337 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2338 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2339 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2340 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2343 R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
2344 R_Shadow_RenderMode_Reset();
2345 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2347 GL_DepthFunc(GL_EQUAL);
2348 // do global setup needed for the chosen lighting mode
2349 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2350 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2351 r_shadow_usingshadowmap2d = shadowmapping;
2352 r_shadow_rendermode = r_shadow_lightingrendermode;
2353 // only draw light where this geometry was already rendered AND the
2354 // stencil is 128 (values other than this mean shadow)
2356 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2358 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2361 static const unsigned short bboxelements[36] =
2371 static const float bboxpoints[8][3] =
2383 void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping)
2386 float vertex3f[8*3];
2387 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2388 // do global setup needed for the chosen lighting mode
2389 R_Shadow_RenderMode_Reset();
2390 r_shadow_rendermode = r_shadow_lightingrendermode;
2391 R_EntityMatrix(&identitymatrix);
2392 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2393 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2394 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
2395 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2397 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
2399 r_shadow_usingshadowmap2d = shadowmapping;
2401 // render the lighting
2402 R_SetupShader_DeferredLight(rsurface.rtlight);
2403 for (i = 0;i < 8;i++)
2404 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2405 GL_ColorMask(1,1,1,1);
2406 GL_DepthMask(false);
2407 GL_DepthRange(0, 1);
2408 GL_PolygonOffset(0, 0);
2410 GL_DepthFunc(GL_GREATER);
2411 GL_CullFace(r_refdef.view.cullface_back);
2412 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
2413 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2416 #define MAXBOUNCEGRIDSPLATSIZE 7
2417 #define MAXBOUNCEGRIDSPLATSIZE1 (MAXBOUNCEGRIDSPLATSIZE+1)
2419 // these are temporary data per-frame, sorted and performed in a more
2420 // cache-friendly order than the original photons
2421 typedef struct r_shadow_bouncegrid_splatpath_s
2427 vec_t splatintensity;
2428 int remainingsplats;
2430 r_shadow_bouncegrid_splatpath_t;
2432 static void R_Shadow_BounceGrid_AddSplatPath(vec3_t originalstart, vec3_t originalend, vec3_t color)
2442 r_shadow_bouncegrid_splatpath_t *path;
2444 // cull paths that fail R_CullBox in dynamic mode
2445 if (!r_shadow_bouncegrid_state.settings.staticmode
2446 && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
2448 vec3_t cullmins, cullmaxs;
2449 cullmins[0] = min(originalstart[0], originalend[0]) - r_shadow_bouncegrid_state.settings.spacing[0];
2450 cullmins[1] = min(originalstart[1], originalend[1]) - r_shadow_bouncegrid_state.settings.spacing[1];
2451 cullmins[2] = min(originalstart[2], originalend[2]) - r_shadow_bouncegrid_state.settings.spacing[2];
2452 cullmaxs[0] = max(originalstart[0], originalend[0]) + r_shadow_bouncegrid_state.settings.spacing[0];
2453 cullmaxs[1] = max(originalstart[1], originalend[1]) + r_shadow_bouncegrid_state.settings.spacing[1];
2454 cullmaxs[2] = max(originalstart[2], originalend[2]) + r_shadow_bouncegrid_state.settings.spacing[2];
2455 if (R_CullBox(cullmins, cullmaxs))
2459 // if the light path is going upward, reverse it - we always draw down.
2460 if (originalend[2] < originalstart[2])
2462 VectorCopy(originalend, start);
2463 VectorCopy(originalstart, end);
2467 VectorCopy(originalstart, start);
2468 VectorCopy(originalend, end);
2471 // transform to texture pixels
2472 start[0] = (start[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2473 start[1] = (start[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2474 start[2] = (start[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2475 end[0] = (end[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2476 end[1] = (end[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2477 end[2] = (end[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2479 // check if we need to grow the splatpaths array
2480 if (r_shadow_bouncegrid_state.maxsplatpaths <= r_shadow_bouncegrid_state.numsplatpaths)
2482 // double the limit, this will persist from frame to frame so we don't
2483 // make the same mistake each time
2484 r_shadow_bouncegrid_state.maxsplatpaths *= 2;
2485 if (r_shadow_bouncegrid_state.maxsplatpaths < 16384)
2486 r_shadow_bouncegrid_state.maxsplatpaths = 16384;
2487 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);
2490 // divide a series of splats along the length using the maximum axis
2491 VectorSubtract(end, start, diff);
2492 // pick the best axis to trace along
2494 if (diff[1]*diff[1] > diff[bestaxis]*diff[bestaxis])
2496 if (diff[2]*diff[2] > diff[bestaxis]*diff[bestaxis])
2498 len = fabs(diff[bestaxis]);
2500 numsplats = (int)(floor(len + 0.5f));
2502 numsplats = bound(0, numsplats, 1024);
2504 VectorSubtract(originalstart, originalend, originaldir);
2505 VectorNormalize(originaldir);
2507 path = r_shadow_bouncegrid_state.splatpaths + r_shadow_bouncegrid_state.numsplatpaths++;
2508 VectorCopy(start, path->point);
2509 VectorScale(diff, ilen, path->step);
2510 VectorCopy(color, path->splatcolor);
2511 VectorCopy(originaldir, path->splatdir);
2512 path->splatintensity = VectorLength(color);
2513 path->remainingsplats = numsplats;
2516 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
2518 qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
2525 // see if there are really any lights to render...
2526 if (enable && r_shadow_bouncegrid_static.integer)
2529 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2530 for (lightindex = 0;lightindex < range;lightindex++)
2532 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2533 if (!light || !(light->flags & flag))
2535 rtlight = &light->rtlight;
2536 // when static, we skip styled lights because they tend to change...
2537 if (rtlight->style > 0)
2539 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
2540 if (!VectorLength2(lightcolor))
2550 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
2552 qboolean s = r_shadow_bouncegrid_static.integer != 0;
2553 float spacing = s ? r_shadow_bouncegrid_static_spacing.value : r_shadow_bouncegrid_dynamic_spacing.value;
2554 float bounceminimumintensity = s ? r_shadow_bouncegrid_static_bounceminimumintensity.value : r_shadow_bouncegrid_dynamic_bounceminimumintensity.value;
2556 // prevent any garbage in alignment padded areas as we'll be using memcmp
2557 memset(settings, 0, sizeof(*settings));
2559 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
2560 settings->staticmode = s;
2561 settings->blur = r_shadow_bouncegrid_blur.integer != 0;
2562 settings->floatcolors = bound(0, r_shadow_bouncegrid_floatcolors.integer, 2);
2563 settings->lightpathsize = bound(1, r_shadow_bouncegrid_lightpathsize.integer, MAXBOUNCEGRIDSPLATSIZE);
2564 settings->bounceanglediffuse = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
2565 settings->directionalshading = (s ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_dynamic_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
2566 settings->dlightparticlemultiplier = s ? 0 : r_shadow_bouncegrid_dynamic_dlightparticlemultiplier.value;
2567 settings->hitmodels = s ? false : r_shadow_bouncegrid_dynamic_hitmodels.integer != 0;
2568 settings->includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
2569 settings->lightradiusscale = (s ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_dynamic_lightradiusscale.value);
2570 settings->maxbounce = (s ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_dynamic_maxbounce.integer);
2571 settings->particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
2572 settings->particleintensity = r_shadow_bouncegrid_particleintensity.value * (settings->directionalshading ? 4.0f : 1.0f) * 16384 / (spacing * spacing) / 262144.0f;
2573 settings->maxphotons = s ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_dynamic_maxphotons.integer;
2574 settings->energyperphoton = s ? r_shadow_bouncegrid_static_energyperphoton.value : r_shadow_bouncegrid_dynamic_energyperphoton.value;
2575 settings->spacing[0] = spacing;
2576 settings->spacing[1] = spacing;
2577 settings->spacing[2] = spacing;
2578 settings->stablerandom = s ? 1 : r_shadow_bouncegrid_dynamic_stablerandom.integer;
2579 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
2581 // bound the values for sanity
2582 settings->maxphotons = bound(1, settings->maxphotons, 25000000);
2583 settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
2584 settings->maxbounce = bound(0, settings->maxbounce, 16);
2585 settings->spacing[0] = bound(1, settings->spacing[0], 512);
2586 settings->spacing[1] = bound(1, settings->spacing[1], 512);
2587 settings->spacing[2] = bound(1, settings->spacing[2], 512);
2589 // check if the ram requirements for blur would be excessive and disable it (increase lightpathsize to compensate)
2590 if (spacing < 32 && settings->blur)
2592 settings->blur = false;
2593 settings->lightpathsize += 2;
2597 static void R_Shadow_BounceGrid_UpdateSpacing(void)
2608 r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
2610 // get the spacing values
2611 spacing[0] = settings->spacing[0];
2612 spacing[1] = settings->spacing[1];
2613 spacing[2] = settings->spacing[2];
2614 ispacing[0] = 1.0f / spacing[0];
2615 ispacing[1] = 1.0f / spacing[1];
2616 ispacing[2] = 1.0f / spacing[2];
2618 // calculate texture size enclosing entire world bounds at the spacing
2619 if (r_refdef.scene.worldmodel)
2621 VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
2622 VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
2626 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
2627 VectorSet(maxs, 1048576.0f, 1048576.0f, 1048576.0f);
2629 VectorSubtract(maxs, mins, size);
2630 // now we can calculate the resolution we want
2631 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2632 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2633 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2634 // figure out the exact texture size (honoring power of 2 if required)
2635 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2636 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2637 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2638 if (vid.support.arb_texture_non_power_of_two)
2640 resolution[0] = c[0];
2641 resolution[1] = c[1];
2642 resolution[2] = c[2];
2646 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2647 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2648 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2650 size[0] = spacing[0] * resolution[0];
2651 size[1] = spacing[1] * resolution[1];
2652 size[2] = spacing[2] * resolution[2];
2654 // if dynamic we may or may not want to use the world bounds
2655 // if the dynamic size is smaller than the world bounds, use it instead
2656 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]))
2658 // we know the resolution we want
2659 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
2660 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
2661 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
2662 // now we can calculate the texture size (power of 2 if required)
2663 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2664 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2665 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2666 if (vid.support.arb_texture_non_power_of_two)
2668 resolution[0] = c[0];
2669 resolution[1] = c[1];
2670 resolution[2] = c[2];
2674 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2675 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2676 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2678 size[0] = spacing[0] * resolution[0];
2679 size[1] = spacing[1] * resolution[1];
2680 size[2] = spacing[2] * resolution[2];
2681 // center the rendering on the view
2682 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2683 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2684 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2687 // recalculate the maxs in case the resolution was not satisfactory
2688 VectorAdd(mins, size, maxs);
2690 // check if this changed the texture size
2691 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);
2692 r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
2693 VectorCopy(mins, r_shadow_bouncegrid_state.mins);
2694 VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
2695 VectorCopy(size, r_shadow_bouncegrid_state.size);
2696 VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
2697 VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
2698 VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
2700 // reallocate pixels for this update if needed...
2701 r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
2702 r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
2703 r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
2704 numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
2705 if (r_shadow_bouncegrid_state.numpixels != numpixels)
2707 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
2708 r_shadow_bouncegrid_state.highpixels = NULL;
2709 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2710 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2711 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2712 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2713 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2714 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2715 r_shadow_bouncegrid_state.numpixels = numpixels;
2718 // update the bouncegrid matrix to put it in the world properly
2719 memset(m, 0, sizeof(m));
2720 m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
2721 m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
2722 m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
2723 m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
2724 m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
2725 m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
2727 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
2730 // enumerate world rtlights and sum the overall amount of light in the world,
2731 // from that we can calculate a scaling factor to fairly distribute photons
2732 // to all the lights
2734 // this modifies rtlight->photoncolor and rtlight->photons
2735 static void R_Shadow_BounceGrid_AssignPhotons(r_shadow_bouncegrid_settings_t *settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
2737 float normalphotonscaling;
2738 float photonscaling;
2739 float photonintensity;
2740 float photoncount = 0.0f;
2741 float lightintensity;
2747 unsigned int lightindex;
2750 normalphotonscaling = 1.0f / max(0.0001f, settings->energyperphoton);
2751 for (lightindex = 0; lightindex < range2; lightindex++)
2753 if (lightindex < range)
2755 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2758 rtlight = &light->rtlight;
2759 VectorClear(rtlight->bouncegrid_photoncolor);
2760 rtlight->bouncegrid_photons = 0;
2761 rtlight->bouncegrid_hits = 0;
2762 rtlight->bouncegrid_traces = 0;
2763 rtlight->bouncegrid_effectiveradius = 0;
2764 if (!(light->flags & flag))
2766 if (settings->staticmode)
2768 // when static, we skip styled lights because they tend to change...
2769 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2772 else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
2777 rtlight = r_refdef.scene.lights[lightindex - range];
2778 VectorClear(rtlight->bouncegrid_photoncolor);
2779 rtlight->bouncegrid_photons = 0;
2780 rtlight->bouncegrid_hits = 0;
2781 rtlight->bouncegrid_traces = 0;
2782 rtlight->bouncegrid_effectiveradius = 0;
2784 // draw only visible lights (major speedup)
2785 radius = rtlight->radius * settings->lightradiusscale;
2786 cullmins[0] = rtlight->shadoworigin[0] - radius;
2787 cullmins[1] = rtlight->shadoworigin[1] - radius;
2788 cullmins[2] = rtlight->shadoworigin[2] - radius;
2789 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2790 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2791 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2792 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2793 if (!settings->staticmode)
2795 if (R_CullBox(cullmins, cullmaxs))
2797 if (r_refdef.scene.worldmodel
2798 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2799 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2801 if (w * VectorLength2(rtlight->color) == 0.0f)
2804 // a light that does not emit any light before style is applied, can be
2805 // skipped entirely (it may just be a corona)
2806 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2808 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2809 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2810 // skip lights that will emit no photons
2811 if (VectorLength2(rtlight->bouncegrid_photoncolor) <= 0.0f)
2813 // shoot particles from this light
2814 // use a calculation for the number of particles that will not
2815 // vary with lightstyle, otherwise we get randomized particle
2816 // distribution, the seeded random is only consistent for a
2817 // consistent number of particles on this light...
2818 s = rtlight->radius;
2819 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2820 if (lightindex >= range)
2821 lightintensity *= settings->dlightparticlemultiplier;
2822 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2823 photoncount += rtlight->bouncegrid_photons;
2824 VectorScale(rtlight->bouncegrid_photoncolor, settings->particleintensity * settings->energyperphoton, rtlight->bouncegrid_photoncolor);
2825 // if the lightstyle happens to be off right now, we can skip actually
2826 // firing the photons, but we did have to count them in the total.
2827 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2828 // rtlight->bouncegrid_photons = 0;
2830 // the user provided an energyperphoton value which we try to use
2831 // if that results in too many photons to shoot this frame, then we cap it
2832 // which causes photons to appear/disappear from frame to frame, so we don't
2833 // like doing that in the typical case
2834 photonscaling = 1.0f;
2835 photonintensity = 1.0f;
2836 if (photoncount > settings->maxphotons)
2838 photonscaling = settings->maxphotons / photoncount;
2839 photonintensity = 1.0f / photonscaling;
2842 // modify the lights to reflect our computed scaling
2843 for (lightindex = 0; lightindex < range2; lightindex++)
2845 if (lightindex < range)
2847 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2850 rtlight = &light->rtlight;
2853 rtlight = r_refdef.scene.lights[lightindex - range];
2854 rtlight->bouncegrid_photons *= photonscaling;
2855 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2859 static int R_Shadow_BounceGrid_SplatPathCompare(const void *pa, const void *pb)
2861 r_shadow_bouncegrid_splatpath_t *a = (r_shadow_bouncegrid_splatpath_t *)pa;
2862 r_shadow_bouncegrid_splatpath_t *b = (r_shadow_bouncegrid_splatpath_t *)pb;
2863 // we only really care about sorting by Z
2864 if (a->point[2] < b->point[2])
2866 if (a->point[2] > b->point[2])
2871 static void R_Shadow_BounceGrid_ClearPixels(void)
2873 // clear the highpixels array we'll be accumulating into
2874 if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2875 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2876 if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2877 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2878 r_shadow_bouncegrid_state.highpixels_index = 0;
2879 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2880 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2883 static void R_Shadow_BounceGrid_PerformSplats(void)
2885 int splatsize = r_shadow_bouncegrid_state.settings.lightpathsize;
2886 int splatsize1 = splatsize + 1;
2887 r_shadow_bouncegrid_splatpath_t *splatpaths = r_shadow_bouncegrid_state.splatpaths;
2888 r_shadow_bouncegrid_splatpath_t *splatpath;
2889 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2890 int numsplatpaths = r_shadow_bouncegrid_state.numsplatpaths;
2896 float texlerp[MAXBOUNCEGRIDSPLATSIZE1][3];
2897 float splatcolor[32];
2898 float boxweight = 1.0f / (splatsize * splatsize * splatsize);
2901 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2902 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2906 // hush warnings about uninitialized data - pixelbands doesn't change but...
2907 memset(splatcolor, 0, sizeof(splatcolor));
2909 // we use this a lot, so get a local copy
2910 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2912 // sort the splats before we execute them, to reduce cache misses
2913 if (r_shadow_bouncegrid_sortlightpaths.integer)
2914 qsort(splatpaths, numsplatpaths, sizeof(*splatpaths), R_Shadow_BounceGrid_SplatPathCompare);
2916 // the middle row/column/layer of each splat are full intensity
2917 for (step = 1;step < splatsize;step++)
2918 VectorSet(texlerp[step], 1.0f, 1.0f, 1.0f);
2920 splatpath = splatpaths;
2921 for (splatindex = 0;splatindex < numsplatpaths;splatindex++, splatpath++)
2923 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2924 // accumulate average shotcolor
2925 VectorCopy(splatpath->splatdir, dir);
2926 splatcolor[ 0] = splatpath->splatcolor[0];
2927 splatcolor[ 1] = splatpath->splatcolor[1];
2928 splatcolor[ 2] = splatpath->splatcolor[2];
2929 splatcolor[ 3] = 0.0f;
2932 // store bentnormal in case the shader has a use for it,
2933 // bentnormal is an intensity-weighted average of the directions,
2934 // and will be normalized on conversion to texture pixels.
2935 splatcolor[ 4] = dir[0] * splatpath->splatintensity;
2936 splatcolor[ 5] = dir[1] * splatpath->splatintensity;
2937 splatcolor[ 6] = dir[2] * splatpath->splatintensity;
2938 splatcolor[ 7] = splatpath->splatintensity;
2939 // for each color component (R, G, B) calculate the amount that a
2940 // direction contributes
2941 splatcolor[ 8] = splatcolor[0] * max(0.0f, dir[0]);
2942 splatcolor[ 9] = splatcolor[0] * max(0.0f, dir[1]);
2943 splatcolor[10] = splatcolor[0] * max(0.0f, dir[2]);
2944 splatcolor[11] = 0.0f;
2945 splatcolor[12] = splatcolor[1] * max(0.0f, dir[0]);
2946 splatcolor[13] = splatcolor[1] * max(0.0f, dir[1]);
2947 splatcolor[14] = splatcolor[1] * max(0.0f, dir[2]);
2948 splatcolor[15] = 0.0f;
2949 splatcolor[16] = splatcolor[2] * max(0.0f, dir[0]);
2950 splatcolor[17] = splatcolor[2] * max(0.0f, dir[1]);
2951 splatcolor[18] = splatcolor[2] * max(0.0f, dir[2]);
2952 splatcolor[19] = 0.0f;
2953 // and do the same for negative directions
2954 splatcolor[20] = splatcolor[0] * max(0.0f, -dir[0]);
2955 splatcolor[21] = splatcolor[0] * max(0.0f, -dir[1]);
2956 splatcolor[22] = splatcolor[0] * max(0.0f, -dir[2]);
2957 splatcolor[23] = 0.0f;
2958 splatcolor[24] = splatcolor[1] * max(0.0f, -dir[0]);
2959 splatcolor[25] = splatcolor[1] * max(0.0f, -dir[1]);
2960 splatcolor[26] = splatcolor[1] * max(0.0f, -dir[2]);
2961 splatcolor[27] = 0.0f;
2962 splatcolor[28] = splatcolor[2] * max(0.0f, -dir[0]);
2963 splatcolor[29] = splatcolor[2] * max(0.0f, -dir[1]);
2964 splatcolor[30] = splatcolor[2] * max(0.0f, -dir[2]);
2965 splatcolor[31] = 0.0f;
2967 // calculate the number of steps we need to traverse this distance
2968 VectorCopy(splatpath->point, steppos);
2969 VectorCopy(splatpath->step, stepdelta);
2970 numsteps = splatpath->remainingsplats;
2971 for (step = 0;step < numsteps;step++)
2973 r_refdef.stats[r_stat_bouncegrid_splats]++;
2974 // figure out the min corner of the pixels we'll need to update
2975 texcorner[0] = steppos[0] - (splatsize1 * 0.5f);
2976 texcorner[1] = steppos[1] - (splatsize1 * 0.5f);
2977 texcorner[2] = steppos[2] - (splatsize1 * 0.5f);
2978 tex[0] = (int)floor(texcorner[0]);
2979 tex[1] = (int)floor(texcorner[1]);
2980 tex[2] = (int)floor(texcorner[2]);
2981 // only update if it is within reasonable bounds
2985 && tex[0] < resolution[0] - splatsize1
2986 && tex[1] < resolution[1] - splatsize1
2987 && tex[2] < resolution[2] - splatsize1)
2989 // it is within bounds... do the real work now
2992 // calculate the antialiased box edges
2993 texlerp[splatsize][0] = texcorner[0] - tex[0];
2994 texlerp[splatsize][1] = texcorner[1] - tex[1];
2995 texlerp[splatsize][2] = texcorner[2] - tex[2];
2996 texlerp[0][0] = 1.0f - texlerp[splatsize][0];
2997 texlerp[0][1] = 1.0f - texlerp[splatsize][1];
2998 texlerp[0][2] = 1.0f - texlerp[splatsize][2];
3000 // accumulate light onto the pixels
3001 for (zi = 0;zi < splatsize1;zi++)
3003 for (yi = 0;yi < splatsize1;yi++)
3005 int index = ((tex[2]+zi)*resolution[1]+tex[1]+yi)*resolution[0]+tex[0];
3006 for (xi = 0;xi < splatsize1;xi++, index++)
3008 float w = texlerp[xi][0]*texlerp[yi][1]*texlerp[zi][2] * boxweight;
3010 float *p = highpixels + 4 * index + band * pixelsperband * 4;
3011 for (;band < pixelbands;band++, p += pixelsperband * 4)
3013 // add to the pixel color
3014 p[0] += splatcolor[band*4+0] * w;
3015 p[1] += splatcolor[band*4+1] * w;
3016 p[2] += splatcolor[band*4+2] * w;
3017 p[3] += splatcolor[band*4+3] * w;
3023 VectorAdd(steppos, stepdelta, steppos);
3028 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
3030 const float *inpixel;
3032 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
3035 unsigned int x, y, z;
3036 unsigned int resolution[3];
3037 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3038 for (pixelband = 0;pixelband < pixelbands;pixelband++)
3040 for (z = 1;z < resolution[2]-1;z++)
3042 for (y = 1;y < resolution[1]-1;y++)
3045 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3046 inpixel = inpixels + 4*index;
3047 outpixel = outpixels + 4*index;
3048 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
3050 outpixel[0] = (inpixel[0] + inpixel[ off] + inpixel[0-off]) * (1.0f / 3.0);
3051 outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
3052 outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
3053 outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
3060 static void R_Shadow_BounceGrid_BlurPixels(void)
3063 unsigned int resolution[3];
3065 if (!r_shadow_bouncegrid_state.settings.blur)
3068 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3070 pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3071 pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
3072 pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3073 pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
3076 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
3078 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
3080 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
3082 // toggle the state, highpixels now points to pixels[3] result
3083 r_shadow_bouncegrid_state.highpixels_index ^= 1;
3084 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3087 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
3089 int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
3090 unsigned char *pixelsbgra8 = NULL;
3091 unsigned char *pixelbgra8;
3092 unsigned short *pixelsrgba16f = NULL;
3093 unsigned short *pixelrgba16f;
3094 float *pixelsrgba32f = NULL;
3095 float *highpixels = r_shadow_bouncegrid_state.highpixels;
3098 unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
3099 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
3100 unsigned int pixelband;
3101 unsigned int x, y, z;
3102 unsigned int index, bandindex;
3103 unsigned int resolution[3];
3105 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3107 if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
3109 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3110 r_shadow_bouncegrid_state.texture = NULL;
3113 // if bentnormals exist, we need to normalize and bias them for the shader
3117 for (z = 0;z < resolution[2]-1;z++)
3119 for (y = 0;y < resolution[1]-1;y++)
3122 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3123 highpixel = highpixels + 4*index;
3124 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3126 // only convert pixels that were hit by photons
3127 if (highpixel[3] != 0.0f)
3128 VectorNormalize(highpixel);
3129 VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
3130 highpixel[pixelsperband * 4 + 3] = 1.0f;
3136 // start by clearing the pixels array - we won't be writing to all of it
3138 // then process only the pixels that have at least some color, skipping
3139 // the higher bands for speed on pixels that are black
3140 switch (floatcolors)
3143 if (r_shadow_bouncegrid_state.u8pixels == NULL)
3144 r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
3145 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
3146 for (pixelband = 0;pixelband < pixelbands;pixelband++)
3149 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
3151 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
3153 for (z = 1;z < resolution[2]-1;z++)
3155 for (y = 1;y < resolution[1]-1;y++)
3159 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3160 highpixel = highpixels + 4*index;
3161 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3163 // only convert pixels that were hit by photons
3164 if (VectorLength2(highpixel))
3166 // normalize the bentnormal now
3169 VectorNormalize(highpixel + pixelsperband * 4);
3170 highpixel[pixelsperband * 4 + 3] = 1.0f;
3172 // process all of the pixelbands for this pixel
3173 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3175 pixelbgra8 = pixelsbgra8 + 4*bandindex;
3176 bandpixel = highpixels + 4*bandindex;
3177 c[0] = (int)(bandpixel[0]*256.0f);
3178 c[1] = (int)(bandpixel[1]*256.0f);
3179 c[2] = (int)(bandpixel[2]*256.0f);
3180 c[3] = (int)(bandpixel[3]*256.0f);
3181 pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
3182 pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
3183 pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
3184 pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
3191 if (!r_shadow_bouncegrid_state.createtexture)
3192 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3194 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);
3197 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
3198 r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3199 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
3200 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3201 for (z = 1;z < resolution[2]-1;z++)
3203 for (y = 1;y < resolution[1]-1;y++)
3207 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3208 highpixel = highpixels + 4*index;
3209 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3211 // only convert pixels that were hit by photons
3212 if (VectorLength2(highpixel))
3214 // process all of the pixelbands for this pixel
3215 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3217 // time to have fun with IEEE 754 bit hacking...
3220 unsigned int raw[4];
3222 pixelrgba16f = pixelsrgba16f + 4*bandindex;
3223 bandpixel = highpixels + 4*bandindex;
3224 VectorCopy4(bandpixel, u.f);
3225 VectorCopy4(u.raw, c);
3226 // this math supports negative numbers, snaps denormals to zero
3227 //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
3228 //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
3229 //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
3230 //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
3231 // this math does not support negative
3232 pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
3233 pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
3234 pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
3235 pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
3242 if (!r_shadow_bouncegrid_state.createtexture)
3243 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 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, (const unsigned char *)pixelsrgba16f, TEXTYPE_COLORBUFFER16F, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, 0, NULL);
3248 // our native format happens to match, so this is easy.
3249 pixelsrgba32f = highpixels;
3251 if (!r_shadow_bouncegrid_state.createtexture)
3252 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3254 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);
3258 r_shadow_bouncegrid_state.lastupdatetime = realtime;
3261 static void R_Shadow_BounceGrid_TracePhotons(r_shadow_bouncegrid_settings_t settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
3263 vec3_t bouncerandom[10];
3266 int hitsupercontentsmask;
3267 int skipsupercontentsmask;
3271 float bounceminimumintensity2;
3273 //trace_t cliptrace2;
3274 //trace_t cliptrace3;
3275 unsigned int lightindex;
3276 unsigned int seed = (unsigned int)(realtime * 1000.0f);
3277 randomseed_t randomseed;
3279 vec3_t baseshotcolor;
3288 Math_RandomSeed_FromInt(&randomseed, seed);
3290 r_shadow_bouncegrid_state.numsplatpaths = 0;
3292 // figure out what we want to interact with
3293 if (settings.hitmodels)
3294 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;// | SUPERCONTENTS_LIQUIDSMASK;
3296 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
3297 skipsupercontentsmask = SUPERCONTENTS_SKY; // skipsurfaces with this contents, even if they also have SUPERCONTENTS_SOLID (basically this is for e1m5.bsp sky trick)
3298 maxbounce = settings.maxbounce;
3300 for (lightindex = 0;lightindex < range2;lightindex++)
3302 if (lightindex < range)
3304 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3307 rtlight = &light->rtlight;
3310 rtlight = r_refdef.scene.lights[lightindex - range];
3311 // note that this code used to keep track of residual photons and
3312 // distribute them evenly to achieve exactly a desired photon count,
3313 // but that caused unwanted flickering in dynamic mode
3314 shootparticles = (int)floor(rtlight->bouncegrid_photons);
3315 // skip if we won't be shooting any photons
3316 if (!shootparticles)
3318 radius = rtlight->radius * settings.lightradiusscale;
3319 //s = settings.particleintensity / shootparticles;
3320 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
3321 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
3322 if (VectorLength2(baseshotcolor) <= 0.0f)
3324 r_refdef.stats[r_stat_bouncegrid_lights]++;
3325 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
3326 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
3327 bounceminimumintensity2 = VectorLength(baseshotcolor) * settings.bounceminimumintensity2;
3328 switch (settings.stablerandom)
3333 Math_RandomSeed_FromInt(&randomseed, lightindex * 11937);
3334 // prime the random number generator a bit
3335 Math_crandomf(&randomseed);
3338 seed = lightindex * 11937;
3339 // prime the random number generator a bit
3343 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
3345 VectorCopy(baseshotcolor, shotcolor);
3346 VectorCopy(rtlight->shadoworigin, clipstart);
3347 switch (settings.stablerandom)
3351 VectorRandom(clipend);
3352 if (settings.bounceanglediffuse)
3354 // we want random to be stable, so we still have to do all the random we would have done
3355 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3356 VectorRandom(bouncerandom[bouncecount]);
3361 VectorLehmerRandom(&randomseed, clipend);
3362 if (settings.bounceanglediffuse)
3364 // we want random to be stable, so we still have to do all the random we would have done
3365 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3366 VectorLehmerRandom(&randomseed, bouncerandom[bouncecount]);
3371 VectorCheeseRandom(seed, clipend);
3372 if (settings.bounceanglediffuse)
3374 // we want random to be stable, so we still have to do all the random we would have done
3375 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3376 VectorCheeseRandom(seed, bouncerandom[bouncecount]);
3380 VectorMA(clipstart, radius, clipend, clipend);
3381 for (bouncecount = 0;;bouncecount++)
3383 r_refdef.stats[r_stat_bouncegrid_traces]++;
3384 rtlight->bouncegrid_traces++;
3385 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
3386 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
3387 if (settings.staticmode || settings.stablerandom <= 0)
3389 // static mode fires a LOT of rays but none of them are identical, so they are not cached
3390 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
3391 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);
3395 // dynamic mode fires many rays and most will match the cache from the previous frame
3396 cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS, hitsupercontentsmask, skipsupercontentsmask);
3398 if (bouncecount > 0 || settings.includedirectlighting)
3401 VectorCopy(cliptrace.endpos, hitpos);
3402 R_Shadow_BounceGrid_AddSplatPath(clipstart, hitpos, shotcolor);
3404 s = VectorDistance(rtlight->shadoworigin, cliptrace.endpos);
3405 if (rtlight->bouncegrid_effectiveradius < s)
3406 rtlight->bouncegrid_effectiveradius = s;
3407 if (cliptrace.fraction >= 1.0f)
3409 r_refdef.stats[r_stat_bouncegrid_hits]++;
3410 rtlight->bouncegrid_hits++;
3411 if (bouncecount >= maxbounce)
3413 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
3414 // also clamp the resulting color to never add energy, even if the user requests extreme values
3415 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
3416 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
3418 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
3419 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
3420 surfcolor[0] = min(surfcolor[0], 1.0f);
3421 surfcolor[1] = min(surfcolor[1], 1.0f);
3422 surfcolor[2] = min(surfcolor[2], 1.0f);
3423 VectorMultiply(shotcolor, surfcolor, shotcolor);
3424 if (VectorLength2(shotcolor) <= bounceminimumintensity2)
3426 r_refdef.stats[r_stat_bouncegrid_bounces]++;
3427 if (settings.bounceanglediffuse)
3429 // random direction, primarily along plane normal
3430 s = VectorDistance(cliptrace.endpos, clipend);
3431 VectorMA(cliptrace.plane.normal, 0.95f, bouncerandom[bouncecount], clipend);
3432 VectorNormalize(clipend);
3433 VectorScale(clipend, s, clipend);
3437 // reflect the remaining portion of the line across plane normal
3438 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
3439 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
3441 // calculate the new line start and end
3442 VectorCopy(cliptrace.endpos, clipstart);
3443 VectorAdd(clipstart, clipend, clipend);
3449 void R_Shadow_UpdateBounceGridTexture(void)
3451 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3452 r_shadow_bouncegrid_settings_t settings;
3453 qboolean enable = false;
3454 qboolean settingschanged;
3455 unsigned int range; // number of world lights
3456 unsigned int range1; // number of dynamic lights (or zero if disabled)
3457 unsigned int range2; // range+range1
3459 enable = R_Shadow_BounceGrid_CheckEnable(flag);
3461 R_Shadow_BounceGrid_GenerateSettings(&settings);
3463 // changing intensity does not require an update
3464 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
3466 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
3468 // when settings change, we free everything as it is just simpler that way.
3469 if (settingschanged || !enable)
3471 // not enabled, make sure we free anything we don't need anymore.
3472 if (r_shadow_bouncegrid_state.texture)
3474 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3475 r_shadow_bouncegrid_state.texture = NULL;
3477 r_shadow_bouncegrid_state.highpixels = NULL;
3478 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
3479 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
3480 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
3481 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
3482 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
3483 r_shadow_bouncegrid_state.maxsplatpaths = 0;
3484 r_shadow_bouncegrid_state.numpixels = 0;
3485 r_shadow_bouncegrid_state.directional = false;
3491 // if all the settings seem identical to the previous update, return
3492 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
3495 // store the new settings
3496 r_shadow_bouncegrid_state.settings = settings;
3498 R_Shadow_BounceGrid_UpdateSpacing();
3500 // get the range of light numbers we'll be looping over:
3501 // range = static lights
3502 // range1 = dynamic lights (optional)
3503 // range2 = range + range1
3504 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3505 range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
3506 range2 = range + range1;
3508 // calculate weighting factors for distributing photons among the lights
3509 R_Shadow_BounceGrid_AssignPhotons(&settings, range, range1, range2, flag);
3511 // trace the photons from lights and accumulate illumination
3512 R_Shadow_BounceGrid_TracePhotons(settings, range, range1, range2, flag);
3514 // clear the texture
3515 R_Shadow_BounceGrid_ClearPixels();
3517 // accumulate the light splatting into texture
3518 R_Shadow_BounceGrid_PerformSplats();
3520 // apply a mild blur filter to the texture
3521 R_Shadow_BounceGrid_BlurPixels();
3523 // convert the pixels to lower precision and upload the texture
3524 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
3526 // after we compute the static lighting we don't need to keep the highpixels array around
3527 if (settings.staticmode)
3529 r_shadow_bouncegrid_state.highpixels = NULL;
3530 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
3531 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
3532 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
3533 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
3534 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
3535 r_shadow_bouncegrid_state.maxsplatpaths = 0;
3539 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
3541 R_Shadow_RenderMode_Reset();
3542 GL_BlendFunc(GL_ONE, GL_ONE);
3543 GL_DepthRange(0, 1);
3544 GL_DepthTest(r_showshadowvolumes.integer < 2);
3545 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
3546 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
3547 GL_CullFace(GL_NONE);
3548 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
3551 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
3553 R_Shadow_RenderMode_Reset();
3554 GL_BlendFunc(GL_ONE, GL_ONE);
3555 GL_DepthRange(0, 1);
3556 GL_DepthTest(r_showlighting.integer < 2);
3557 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
3559 GL_DepthFunc(GL_EQUAL);
3560 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
3561 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
3564 void R_Shadow_RenderMode_End(void)
3566 R_Shadow_RenderMode_Reset();
3567 R_Shadow_RenderMode_ActiveLight(NULL);
3569 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3570 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3573 int bboxedges[12][2] =
3592 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
3594 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
3596 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
3597 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
3598 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
3599 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
3602 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
3603 return true; // invisible
3604 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
3605 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
3606 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
3607 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
3608 r_refdef.stats[r_stat_lights_scissored]++;
3612 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
3615 const float *vertex3f;
3616 const float *normal3f;
3618 float dist, dot, distintensity, shadeintensity, v[3], n[3];
3619 switch (r_shadow_rendermode)
3621 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3622 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3623 if (VectorLength2(diffusecolor) > 0)
3625 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)
3627 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3628 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3629 if ((dot = DotProduct(n, v)) < 0)
3631 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3632 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
3635 VectorCopy(ambientcolor, color4f);
3636 if (r_refdef.fogenabled)
3639 f = RSurf_FogVertex(vertex3f);
3640 VectorScale(color4f, f, color4f);
3647 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3649 VectorCopy(ambientcolor, color4f);
3650 if (r_refdef.fogenabled)
3653 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3654 f = RSurf_FogVertex(vertex3f);
3655 VectorScale(color4f + 4*i, f, color4f);
3661 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3662 if (VectorLength2(diffusecolor) > 0)
3664 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)
3666 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3667 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3669 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3670 if ((dot = DotProduct(n, v)) < 0)
3672 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3673 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3674 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3675 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3679 color4f[0] = ambientcolor[0] * distintensity;
3680 color4f[1] = ambientcolor[1] * distintensity;
3681 color4f[2] = ambientcolor[2] * distintensity;
3683 if (r_refdef.fogenabled)
3686 f = RSurf_FogVertex(vertex3f);
3687 VectorScale(color4f, f, color4f);
3691 VectorClear(color4f);
3697 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3699 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3700 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3702 color4f[0] = ambientcolor[0] * distintensity;
3703 color4f[1] = ambientcolor[1] * distintensity;
3704 color4f[2] = ambientcolor[2] * distintensity;
3705 if (r_refdef.fogenabled)
3708 f = RSurf_FogVertex(vertex3f);
3709 VectorScale(color4f, f, color4f);
3713 VectorClear(color4f);
3718 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3719 if (VectorLength2(diffusecolor) > 0)
3721 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)
3723 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3724 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3726 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3727 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3728 if ((dot = DotProduct(n, v)) < 0)
3730 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3731 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3732 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3733 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3737 color4f[0] = ambientcolor[0] * distintensity;
3738 color4f[1] = ambientcolor[1] * distintensity;
3739 color4f[2] = ambientcolor[2] * distintensity;
3741 if (r_refdef.fogenabled)
3744 f = RSurf_FogVertex(vertex3f);
3745 VectorScale(color4f, f, color4f);
3749 VectorClear(color4f);
3755 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3757 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3758 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3760 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3761 color4f[0] = ambientcolor[0] * distintensity;
3762 color4f[1] = ambientcolor[1] * distintensity;
3763 color4f[2] = ambientcolor[2] * distintensity;
3764 if (r_refdef.fogenabled)
3767 f = RSurf_FogVertex(vertex3f);
3768 VectorScale(color4f, f, color4f);
3772 VectorClear(color4f);
3782 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3784 // used to display how many times a surface is lit for level design purposes
3785 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3786 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3790 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
3792 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3793 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
3797 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3804 int newnumtriangles;
3808 int maxtriangles = 1024;
3809 int newelements[1024*3];
3810 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3811 for (renders = 0;renders < 4;renders++)
3816 newnumtriangles = 0;
3818 // due to low fillrate on the cards this vertex lighting path is
3819 // designed for, we manually cull all triangles that do not
3820 // contain a lit vertex
3821 // this builds batches of triangles from multiple surfaces and
3822 // renders them at once
3823 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3825 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3827 if (newnumtriangles)
3829 newfirstvertex = min(newfirstvertex, e[0]);
3830 newlastvertex = max(newlastvertex, e[0]);
3834 newfirstvertex = e[0];
3835 newlastvertex = e[0];
3837 newfirstvertex = min(newfirstvertex, e[1]);
3838 newlastvertex = max(newlastvertex, e[1]);
3839 newfirstvertex = min(newfirstvertex, e[2]);
3840 newlastvertex = max(newlastvertex, e[2]);
3846 if (newnumtriangles >= maxtriangles)
3848 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3849 newnumtriangles = 0;
3855 if (newnumtriangles >= 1)
3857 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3860 // if we couldn't find any lit triangles, exit early
3863 // now reduce the intensity for the next overbright pass
3864 // we have to clamp to 0 here incase the drivers have improper
3865 // handling of negative colors
3866 // (some old drivers even have improper handling of >1 color)
3868 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3870 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3872 c[0] = max(0, c[0] - 1);
3873 c[1] = max(0, c[1] - 1);
3874 c[2] = max(0, c[2] - 1);
3886 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
3888 // OpenGL 1.1 path (anything)
3889 float ambientcolorbase[3], diffusecolorbase[3];
3890 float ambientcolorpants[3], diffusecolorpants[3];
3891 float ambientcolorshirt[3], diffusecolorshirt[3];
3892 const float *surfacecolor = rsurface.texture->dlightcolor;
3893 const float *surfacepants = rsurface.colormap_pantscolor;
3894 const float *surfaceshirt = rsurface.colormap_shirtcolor;
3895 rtexture_t *basetexture = rsurface.texture->basetexture;
3896 rtexture_t *pantstexture = rsurface.texture->pantstexture;
3897 rtexture_t *shirttexture = rsurface.texture->shirttexture;
3898 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3899 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3900 ambientscale *= 2 * r_refdef.view.colorscale;
3901 diffusescale *= 2 * r_refdef.view.colorscale;
3902 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3903 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3904 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3905 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3906 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3907 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
3908 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3909 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
3910 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3911 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
3912 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
3913 R_Mesh_TexBind(0, basetexture);
3914 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
3915 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
3916 switch(r_shadow_rendermode)
3918 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3919 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
3920 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3921 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3922 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3924 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3925 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
3926 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
3927 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
3928 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3930 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3931 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
3932 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3933 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3934 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3936 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3941 //R_Mesh_TexBind(0, basetexture);
3942 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
3945 R_Mesh_TexBind(0, pantstexture);
3946 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
3950 R_Mesh_TexBind(0, shirttexture);
3951 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
3955 extern cvar_t gl_lightmaps;
3956 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3958 float ambientscale, diffusescale, specularscale;
3960 float lightcolor[3];
3961 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
3962 ambientscale = rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient;
3963 diffusescale = rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient);
3964 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3965 if (!r_shadow_usenormalmap.integer)
3967 ambientscale += 1.0f * diffusescale;
3971 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
3973 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
3976 VectorNegate(lightcolor, lightcolor);
3977 GL_BlendEquationSubtract(true);
3979 RSurf_SetupDepthAndCulling();
3980 switch (r_shadow_rendermode)
3982 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3983 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3984 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
3986 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3987 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
3989 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3990 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3991 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3992 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3993 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
3996 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
4000 GL_BlendEquationSubtract(false);
4003 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)
4005 matrix4x4_t tempmatrix = *matrix;
4006 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
4008 // if this light has been compiled before, free the associated data
4009 R_RTLight_Uncompile(rtlight);
4011 // clear it completely to avoid any lingering data
4012 memset(rtlight, 0, sizeof(*rtlight));
4014 // copy the properties
4015 rtlight->matrix_lighttoworld = tempmatrix;
4016 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
4017 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
4018 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
4019 VectorCopy(color, rtlight->color);
4020 rtlight->cubemapname[0] = 0;
4021 if (cubemapname && cubemapname[0])
4022 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
4023 rtlight->shadow = shadow;
4024 rtlight->corona = corona;
4025 rtlight->style = style;
4026 rtlight->isstatic = isstatic;
4027 rtlight->coronasizescale = coronasizescale;
4028 rtlight->ambientscale = ambientscale;
4029 rtlight->diffusescale = diffusescale;
4030 rtlight->specularscale = specularscale;
4031 rtlight->flags = flags;
4033 // compute derived data
4034 //rtlight->cullradius = rtlight->radius;
4035 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
4036 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
4037 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
4038 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
4039 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
4040 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
4041 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
4044 // compiles rtlight geometry
4045 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
4046 void R_RTLight_Compile(rtlight_t *rtlight)
4049 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
4050 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
4051 entity_render_t *ent = r_refdef.scene.worldentity;
4052 dp_model_t *model = r_refdef.scene.worldmodel;
4053 unsigned char *data;
4056 // compile the light
4057 rtlight->compiled = true;
4058 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
4059 rtlight->static_numleafs = 0;
4060 rtlight->static_numleafpvsbytes = 0;
4061 rtlight->static_leaflist = NULL;
4062 rtlight->static_leafpvs = NULL;
4063 rtlight->static_numsurfaces = 0;
4064 rtlight->static_surfacelist = NULL;
4065 rtlight->static_shadowmap_receivers = 0x3F;
4066 rtlight->static_shadowmap_casters = 0x3F;
4067 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
4068 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
4069 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
4070 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
4071 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
4072 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
4074 if (model && model->GetLightInfo)
4076 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
4077 r_shadow_compilingrtlight = rtlight;
4078 R_FrameData_SetMark();
4079 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);
4080 R_FrameData_ReturnToMark();
4081 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
4082 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
4083 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
4084 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
4085 rtlight->static_numsurfaces = numsurfaces;
4086 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
4087 rtlight->static_numleafs = numleafs;
4088 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
4089 rtlight->static_numleafpvsbytes = numleafpvsbytes;
4090 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
4091 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
4092 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
4093 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
4094 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
4095 if (rtlight->static_numsurfaces)
4096 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
4097 if (rtlight->static_numleafs)
4098 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
4099 if (rtlight->static_numleafpvsbytes)
4100 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
4101 if (rtlight->static_numshadowtrispvsbytes)
4102 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
4103 if (rtlight->static_numlighttrispvsbytes)
4104 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
4105 R_FrameData_SetMark();
4106 switch (rtlight->shadowmode)
4108 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4109 if (model->CompileShadowMap && rtlight->shadow)
4110 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
4113 if (model->CompileShadowVolume && rtlight->shadow)
4114 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
4117 R_FrameData_ReturnToMark();
4118 // now we're done compiling the rtlight
4119 r_shadow_compilingrtlight = NULL;
4123 // use smallest available cullradius - box radius or light radius
4124 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
4125 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
4127 shadowzpasstris = 0;
4128 if (rtlight->static_meshchain_shadow_zpass)
4129 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
4130 shadowzpasstris += mesh->numtriangles;
4132 shadowzfailtris = 0;
4133 if (rtlight->static_meshchain_shadow_zfail)
4134 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
4135 shadowzfailtris += mesh->numtriangles;
4138 if (rtlight->static_numlighttrispvsbytes)
4139 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
4140 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
4144 if (rtlight->static_numshadowtrispvsbytes)
4145 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
4146 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
4149 if (developer_extra.integer)
4150 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);
4153 void R_RTLight_Uncompile(rtlight_t *rtlight)
4155 if (rtlight->compiled)
4157 if (rtlight->static_meshchain_shadow_zpass)
4158 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
4159 rtlight->static_meshchain_shadow_zpass = NULL;
4160 if (rtlight->static_meshchain_shadow_zfail)
4161 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
4162 rtlight->static_meshchain_shadow_zfail = NULL;
4163 if (rtlight->static_meshchain_shadow_shadowmap)
4164 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
4165 rtlight->static_meshchain_shadow_shadowmap = NULL;
4166 // these allocations are grouped
4167 if (rtlight->static_surfacelist)
4168 Mem_Free(rtlight->static_surfacelist);
4169 rtlight->static_numleafs = 0;
4170 rtlight->static_numleafpvsbytes = 0;
4171 rtlight->static_leaflist = NULL;
4172 rtlight->static_leafpvs = NULL;
4173 rtlight->static_numsurfaces = 0;
4174 rtlight->static_surfacelist = NULL;
4175 rtlight->static_numshadowtrispvsbytes = 0;
4176 rtlight->static_shadowtrispvs = NULL;
4177 rtlight->static_numlighttrispvsbytes = 0;
4178 rtlight->static_lighttrispvs = NULL;
4179 rtlight->compiled = false;
4183 void R_Shadow_UncompileWorldLights(void)
4187 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4188 for (lightindex = 0;lightindex < range;lightindex++)
4190 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4193 R_RTLight_Uncompile(&light->rtlight);
4197 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
4201 // reset the count of frustum planes
4202 // see rtlight->cached_frustumplanes definition for how much this array
4204 rtlight->cached_numfrustumplanes = 0;
4206 if (r_trippy.integer)
4209 // haven't implemented a culling path for ortho rendering
4210 if (!r_refdef.view.useperspective)
4212 // check if the light is on screen and copy the 4 planes if it is
4213 for (i = 0;i < 4;i++)
4214 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4217 for (i = 0;i < 4;i++)
4218 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4223 // generate a deformed frustum that includes the light origin, this is
4224 // used to cull shadow casting surfaces that can not possibly cast a
4225 // shadow onto the visible light-receiving surfaces, which can be a
4228 // if the light origin is onscreen the result will be 4 planes exactly
4229 // if the light origin is offscreen on only one axis the result will
4230 // be exactly 5 planes (split-side case)
4231 // if the light origin is offscreen on two axes the result will be
4232 // exactly 4 planes (stretched corner case)
4233 for (i = 0;i < 4;i++)
4235 // quickly reject standard frustum planes that put the light
4236 // origin outside the frustum
4237 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4240 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4242 // if all the standard frustum planes were accepted, the light is onscreen
4243 // otherwise we need to generate some more planes below...
4244 if (rtlight->cached_numfrustumplanes < 4)
4246 // at least one of the stock frustum planes failed, so we need to
4247 // create one or two custom planes to enclose the light origin
4248 for (i = 0;i < 4;i++)
4250 // create a plane using the view origin and light origin, and a
4251 // single point from the frustum corner set
4252 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
4253 VectorNormalize(plane.normal);
4254 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
4255 // see if this plane is backwards and flip it if so
4256 for (j = 0;j < 4;j++)
4257 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4261 VectorNegate(plane.normal, plane.normal);
4263 // flipped plane, test again to see if it is now valid
4264 for (j = 0;j < 4;j++)
4265 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4267 // if the plane is still not valid, then it is dividing the
4268 // frustum and has to be rejected
4272 // we have created a valid plane, compute extra info
4273 PlaneClassify(&plane);
4275 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4277 // if we've found 5 frustum planes then we have constructed a
4278 // proper split-side case and do not need to keep searching for
4279 // planes to enclose the light origin
4280 if (rtlight->cached_numfrustumplanes == 5)
4288 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
4290 plane = rtlight->cached_frustumplanes[i];
4291 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));
4296 // now add the light-space box planes if the light box is rotated, as any
4297 // caster outside the oriented light box is irrelevant (even if it passed
4298 // the worldspace light box, which is axial)
4299 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
4301 for (i = 0;i < 6;i++)
4305 v[i >> 1] = (i & 1) ? -1 : 1;
4306 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
4307 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
4308 plane.dist = VectorNormalizeLength(plane.normal);
4309 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
4310 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4316 // add the world-space reduced box planes
4317 for (i = 0;i < 6;i++)
4319 VectorClear(plane.normal);
4320 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
4321 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
4322 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4331 // reduce all plane distances to tightly fit the rtlight cull box, which
4333 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4334 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4335 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4336 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4337 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4338 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4339 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4340 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4341 oldnum = rtlight->cached_numfrustumplanes;
4342 rtlight->cached_numfrustumplanes = 0;
4343 for (j = 0;j < oldnum;j++)
4345 // find the nearest point on the box to this plane
4346 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
4347 for (i = 1;i < 8;i++)
4349 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
4350 if (bestdist > dist)
4353 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);
4354 // if the nearest point is near or behind the plane, we want this
4355 // plane, otherwise the plane is useless as it won't cull anything
4356 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
4358 PlaneClassify(&rtlight->cached_frustumplanes[j]);
4359 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
4366 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
4370 RSurf_ActiveWorldEntity();
4372 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4375 GL_CullFace(GL_NONE);
4376 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
4377 for (;mesh;mesh = mesh->next)
4379 if (!mesh->sidetotals[r_shadow_shadowmapside])
4381 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
4382 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4383 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);
4387 else if (r_refdef.scene.worldentity->model)
4388 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);
4390 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4393 static void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
4395 qboolean zpass = false;
4398 int surfacelistindex;
4399 msurface_t *surface;
4401 // if triangle neighbors are disabled, shadowvolumes are disabled
4402 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
4405 RSurf_ActiveWorldEntity();
4407 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4410 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
4412 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
4413 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
4415 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
4416 for (;mesh;mesh = mesh->next)
4418 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->numtriangles;
4419 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4420 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
4422 // increment stencil if frontface is infront of depthbuffer
4423 GL_CullFace(r_refdef.view.cullface_back);
4424 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
4425 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);
4426 // decrement stencil if backface is infront of depthbuffer
4427 GL_CullFace(r_refdef.view.cullface_front);
4428 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
4430 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
4432 // decrement stencil if backface is behind depthbuffer
4433 GL_CullFace(r_refdef.view.cullface_front);
4434 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
4435 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);
4436 // increment stencil if frontface is behind depthbuffer
4437 GL_CullFace(r_refdef.view.cullface_back);
4438 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
4440 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);
4444 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
4446 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
4447 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
4448 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
4450 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
4451 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
4452 if (CHECKPVSBIT(trispvs, t))
4453 shadowmarklist[numshadowmark++] = t;
4455 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);
4457 else if (numsurfaces)
4459 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);
4462 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4465 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
4467 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
4468 vec_t relativeshadowradius;
4469 RSurf_ActiveModelEntity(ent, false, false, false);
4470 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
4471 // we need to re-init the shader for each entity because the matrix changed
4472 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
4473 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
4474 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
4475 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
4476 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
4477 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
4478 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
4479 switch (r_shadow_rendermode)
4481 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
4482 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4485 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4488 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4491 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
4493 // set up properties for rendering light onto this entity
4494 RSurf_ActiveModelEntity(ent, true, true, false);
4495 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
4496 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4497 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4498 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4501 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
4503 if (!r_refdef.scene.worldmodel->DrawLight)
4506 // set up properties for rendering light onto this entity
4507 RSurf_ActiveWorldEntity();
4508 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
4509 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4510 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4511 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4513 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
4515 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4518 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
4520 dp_model_t *model = ent->model;
4521 if (!model->DrawLight)
4524 R_Shadow_SetupEntityLight(ent);
4526 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
4528 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4531 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
4535 int numleafs, numsurfaces;
4536 int *leaflist, *surfacelist;
4537 unsigned char *leafpvs;
4538 unsigned char *shadowtrispvs;
4539 unsigned char *lighttrispvs;
4540 //unsigned char *surfacesides;
4541 int numlightentities;
4542 int numlightentities_noselfshadow;
4543 int numshadowentities;
4544 int numshadowentities_noselfshadow;
4545 // FIXME: bounds check lightentities and shadowentities, etc.
4546 static entity_render_t *lightentities[MAX_EDICTS];
4547 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
4548 static entity_render_t *shadowentities[MAX_EDICTS];
4549 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
4551 qboolean castshadows;
4553 rtlight->draw = false;
4554 rtlight->cached_numlightentities = 0;
4555 rtlight->cached_numlightentities_noselfshadow = 0;
4556 rtlight->cached_numshadowentities = 0;
4557 rtlight->cached_numshadowentities_noselfshadow = 0;
4558 rtlight->cached_numsurfaces = 0;
4559 rtlight->cached_lightentities = NULL;
4560 rtlight->cached_lightentities_noselfshadow = NULL;
4561 rtlight->cached_shadowentities = NULL;
4562 rtlight->cached_shadowentities_noselfshadow = NULL;
4563 rtlight->cached_shadowtrispvs = NULL;
4564 rtlight->cached_lighttrispvs = NULL;
4565 rtlight->cached_surfacelist = NULL;
4566 rtlight->shadowmapsidesize = 0;
4568 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
4569 // skip lights that are basically invisible (color 0 0 0)
4570 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
4572 // loading is done before visibility checks because loading should happen
4573 // all at once at the start of a level, not when it stalls gameplay.
4574 // (especially important to benchmarks)
4576 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
4578 if (rtlight->compiled)
4579 R_RTLight_Uncompile(rtlight);
4580 R_RTLight_Compile(rtlight);
4584 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
4586 // look up the light style value at this time
4587 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4588 VectorScale(rtlight->color, f, rtlight->currentcolor);
4590 if (rtlight->selected)
4592 f = 2 + sin(realtime * M_PI * 4.0);
4593 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
4597 // if lightstyle is currently off, don't draw the light
4598 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
4601 // skip processing on corona-only lights
4605 // if the light box is offscreen, skip it
4606 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
4609 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
4610 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
4612 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4614 // 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
4615 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
4618 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
4620 // compiled light, world available and can receive realtime lighting
4621 // retrieve leaf information
4622 numleafs = rtlight->static_numleafs;
4623 leaflist = rtlight->static_leaflist;
4624 leafpvs = rtlight->static_leafpvs;
4625 numsurfaces = rtlight->static_numsurfaces;
4626 surfacelist = rtlight->static_surfacelist;
4627 //surfacesides = NULL;
4628 shadowtrispvs = rtlight->static_shadowtrispvs;
4629 lighttrispvs = rtlight->static_lighttrispvs;
4631 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4633 // dynamic light, world available and can receive realtime lighting
4634 // calculate lit surfaces and leafs
4635 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);
4636 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4637 leaflist = r_shadow_buffer_leaflist;
4638 leafpvs = r_shadow_buffer_leafpvs;
4639 surfacelist = r_shadow_buffer_surfacelist;
4640 //surfacesides = r_shadow_buffer_surfacesides;
4641 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4642 lighttrispvs = r_shadow_buffer_lighttrispvs;
4643 // if the reduced leaf bounds are offscreen, skip it
4644 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4655 //surfacesides = NULL;
4656 shadowtrispvs = NULL;
4657 lighttrispvs = NULL;
4659 // check if light is illuminating any visible leafs
4662 for (i = 0; i < numleafs; i++)
4663 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4669 // make a list of lit entities and shadow casting entities
4670 numlightentities = 0;
4671 numlightentities_noselfshadow = 0;
4672 numshadowentities = 0;
4673 numshadowentities_noselfshadow = 0;
4675 // add dynamic entities that are lit by the light
4676 for (i = 0; i < r_refdef.scene.numentities; i++)
4679 entity_render_t *ent = r_refdef.scene.entities[i];
4681 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4683 // skip the object entirely if it is not within the valid
4684 // shadow-casting region (which includes the lit region)
4685 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
4687 if (!(model = ent->model))
4689 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4691 // this entity wants to receive light, is visible, and is
4692 // inside the light box
4693 // TODO: check if the surfaces in the model can receive light
4694 // so now check if it's in a leaf seen by the light
4695 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))
4697 if (ent->flags & RENDER_NOSELFSHADOW)
4698 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
4700 lightentities[numlightentities++] = ent;
4701 // since it is lit, it probably also casts a shadow...
4702 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4703 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4704 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4706 // note: exterior models without the RENDER_NOSELFSHADOW
4707 // flag still create a RENDER_NOSELFSHADOW shadow but
4708 // are lit normally, this means that they are
4709 // self-shadowing but do not shadow other
4710 // RENDER_NOSELFSHADOW entities such as the gun
4711 // (very weird, but keeps the player shadow off the gun)
4712 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4713 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4715 shadowentities[numshadowentities++] = ent;
4718 else if (ent->flags & RENDER_SHADOW)
4720 // this entity is not receiving light, but may still need to
4722 // TODO: check if the surfaces in the model can cast shadow
4723 // now check if it is in a leaf seen by the light
4724 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))
4726 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4727 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4728 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4730 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4731 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4733 shadowentities[numshadowentities++] = ent;
4738 // return if there's nothing at all to light
4739 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4742 // count this light in the r_speeds
4743 r_refdef.stats[r_stat_lights]++;
4745 // flag it as worth drawing later
4746 rtlight->draw = true;
4748 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
4749 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4751 numshadowentities = numshadowentities_noselfshadow = 0;
4752 rtlight->castshadows = castshadows;
4754 // cache all the animated entities that cast a shadow but are not visible
4755 for (i = 0; i < numshadowentities; i++)
4756 R_AnimCache_GetEntity(shadowentities[i], false, false);
4757 for (i = 0; i < numshadowentities_noselfshadow; i++)
4758 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4760 // 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)
4761 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
4763 for (i = 0; i < numshadowentities_noselfshadow; i++)
4764 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
4765 numshadowentities_noselfshadow = 0;
4768 // we can convert noselfshadow to regular if there are no casters of that type
4769 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
4771 for (i = 0; i < numlightentities_noselfshadow; i++)
4772 lightentities[numlightentities++] = lightentities_noselfshadow[i];
4773 numlightentities_noselfshadow = 0;
4776 // allocate some temporary memory for rendering this light later in the frame
4777 // reusable buffers need to be copied, static data can be used as-is
4778 rtlight->cached_numlightentities = numlightentities;
4779 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
4780 rtlight->cached_numshadowentities = numshadowentities;
4781 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4782 rtlight->cached_numsurfaces = numsurfaces;
4783 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4784 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4785 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4786 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4787 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4789 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4790 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4791 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4792 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4793 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4797 // compiled light data
4798 rtlight->cached_shadowtrispvs = shadowtrispvs;
4799 rtlight->cached_lighttrispvs = lighttrispvs;
4800 rtlight->cached_surfacelist = surfacelist;
4803 if (R_Shadow_ShadowMappingEnabled())
4805 // figure out the shadowmapping parameters for this light
4806 vec3_t nearestpoint;
4809 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4810 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4811 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4812 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4813 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
4814 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4815 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4816 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4817 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
4821 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
4825 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4826 int numlightentities;
4827 int numlightentities_noselfshadow;
4828 int numshadowentities;
4829 int numshadowentities_noselfshadow;
4830 entity_render_t **lightentities;
4831 entity_render_t **lightentities_noselfshadow;
4832 entity_render_t **shadowentities;
4833 entity_render_t **shadowentities_noselfshadow;
4835 static unsigned char entitysides[MAX_EDICTS];
4836 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4842 matrix4x4_t radiustolight;
4844 // check if we cached this light this frame (meaning it is worth drawing)
4845 if (!rtlight->draw || !rtlight->castshadows)
4848 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
4849 if (rtlight->shadowmapatlassidesize == 0)
4851 rtlight->castshadows = false;
4855 // set up a scissor rectangle for this light
4856 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4859 // don't let sound skip if going slow
4860 if (r_refdef.scene.extraupdate)
4863 numlightentities = rtlight->cached_numlightentities;
4864 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4865 numshadowentities = rtlight->cached_numshadowentities;
4866 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4867 numsurfaces = rtlight->cached_numsurfaces;
4868 lightentities = rtlight->cached_lightentities;
4869 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4870 shadowentities = rtlight->cached_shadowentities;
4871 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4872 shadowtrispvs = rtlight->cached_shadowtrispvs;
4873 lighttrispvs = rtlight->cached_lighttrispvs;
4874 surfacelist = rtlight->cached_surfacelist;
4876 // make this the active rtlight for rendering purposes
4877 R_Shadow_RenderMode_ActiveLight(rtlight);
4879 radiustolight = rtlight->matrix_worldtolight;
4880 Matrix4x4_Abs(&radiustolight);
4882 size = rtlight->shadowmapatlassidesize;
4883 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4885 surfacesides = NULL;
4890 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4892 castermask = rtlight->static_shadowmap_casters;
4893 receivermask = rtlight->static_shadowmap_receivers;
4897 surfacesides = r_shadow_buffer_surfacesides;
4898 for (i = 0; i < numsurfaces; i++)
4900 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4901 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4902 castermask |= surfacesides[i];
4903 receivermask |= surfacesides[i];
4908 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
4909 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4910 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
4911 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4913 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4917 for (i = 0; i < numshadowentities; i++)
4918 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4919 for (i = 0; i < numshadowentities_noselfshadow; i++)
4920 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4923 // there is no need to render shadows for sides that have no receivers...
4924 castermask &= receivermask;
4926 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
4928 // render shadow casters into shadowmaps for this light
4929 for (side = 0; side < 6; side++)
4931 int bit = 1 << side;
4932 if (castermask & bit)
4934 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
4936 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4937 for (i = 0; i < numshadowentities; i++)
4938 if (entitysides[i] & bit)
4939 R_Shadow_DrawEntityShadow(shadowentities[i]);
4940 for (i = 0; i < numshadowentities_noselfshadow; i++)
4941 if (entitysides_noselfshadow[i] & bit)
4942 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4945 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
4946 if (numshadowentities_noselfshadow)
4948 for (side = 0; side < 6; side++)
4950 int bit = 1 << side;
4951 if (castermask & bit)
4953 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
4955 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4956 for (i = 0; i < numshadowentities; i++)
4957 if (entitysides[i] & bit)
4958 R_Shadow_DrawEntityShadow(shadowentities[i]);
4964 static void R_Shadow_DrawLight(rtlight_t *rtlight)
4968 unsigned char *shadowtrispvs, *lighttrispvs;
4969 int numlightentities;
4970 int numlightentities_noselfshadow;
4971 int numshadowentities;
4972 int numshadowentities_noselfshadow;
4973 entity_render_t **lightentities;
4974 entity_render_t **lightentities_noselfshadow;
4975 entity_render_t **shadowentities;
4976 entity_render_t **shadowentities_noselfshadow;
4978 qboolean castshadows;
4980 // check if we cached this light this frame (meaning it is worth drawing)
4984 // set up a scissor rectangle for this light
4985 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4988 // don't let sound skip if going slow
4989 if (r_refdef.scene.extraupdate)
4992 numlightentities = rtlight->cached_numlightentities;
4993 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4994 numshadowentities = rtlight->cached_numshadowentities;
4995 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4996 numsurfaces = rtlight->cached_numsurfaces;
4997 lightentities = rtlight->cached_lightentities;
4998 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4999 shadowentities = rtlight->cached_shadowentities;
5000 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
5001 shadowtrispvs = rtlight->cached_shadowtrispvs;
5002 lighttrispvs = rtlight->cached_lighttrispvs;
5003 surfacelist = rtlight->cached_surfacelist;
5004 castshadows = rtlight->castshadows;
5006 // make this the active rtlight for rendering purposes
5007 R_Shadow_RenderMode_ActiveLight(rtlight);
5009 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
5011 // optionally draw visible shape of the shadow volumes
5012 // for performance analysis by level designers
5013 R_Shadow_RenderMode_VisibleShadowVolumes();
5015 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
5016 for (i = 0;i < numshadowentities;i++)
5017 R_Shadow_DrawEntityShadow(shadowentities[i]);
5018 for (i = 0;i < numshadowentities_noselfshadow;i++)
5019 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5020 R_Shadow_RenderMode_VisibleLighting(false, false);
5023 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
5025 // optionally draw the illuminated areas
5026 // for performance analysis by level designers
5027 R_Shadow_RenderMode_VisibleLighting(false, false);
5029 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5030 for (i = 0;i < numlightentities;i++)
5031 R_Shadow_DrawEntityLight(lightentities[i]);
5032 for (i = 0;i < numlightentities_noselfshadow;i++)
5033 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5036 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
5040 float shadowmapoffsetnoselfshadow = 0;
5041 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
5042 Matrix4x4_Abs(&radiustolight);
5044 size = rtlight->shadowmapatlassidesize;
5045 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
5047 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
5049 if (rtlight->cached_numshadowentities_noselfshadow)
5050 shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
5052 // render lighting using the depth texture as shadowmap
5053 // draw lighting in the unmasked areas
5054 if (numsurfaces + numlightentities)
5056 R_Shadow_RenderMode_Lighting(false, false, true, false);
5057 // draw lighting in the unmasked areas
5059 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5060 for (i = 0; i < numlightentities; i++)
5061 R_Shadow_DrawEntityLight(lightentities[i]);
5063 // offset to the noselfshadow part of the atlas and draw those too
5064 if (numlightentities_noselfshadow)
5066 R_Shadow_RenderMode_Lighting(false, false, true, true);
5067 for (i = 0; i < numlightentities_noselfshadow; i++)
5068 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5071 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5072 if (r_shadow_usingdeferredprepass)
5073 R_Shadow_RenderMode_DrawDeferredLight(true);
5075 else if (castshadows && vid.stencil)
5077 // draw stencil shadow volumes to mask off pixels that are in shadow
5078 // so that they won't receive lighting
5079 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
5080 R_Shadow_ClearStencil();
5083 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
5084 for (i = 0;i < numshadowentities;i++)
5085 R_Shadow_DrawEntityShadow(shadowentities[i]);
5087 // draw lighting in the unmasked areas
5088 R_Shadow_RenderMode_Lighting(true, false, false, false);
5089 for (i = 0;i < numlightentities_noselfshadow;i++)
5090 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5092 for (i = 0;i < numshadowentities_noselfshadow;i++)
5093 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5095 // draw lighting in the unmasked areas
5096 R_Shadow_RenderMode_Lighting(true, false, false, false);
5098 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5099 for (i = 0;i < numlightentities;i++)
5100 R_Shadow_DrawEntityLight(lightentities[i]);
5102 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5103 if (r_shadow_usingdeferredprepass)
5104 R_Shadow_RenderMode_DrawDeferredLight(false);
5108 // draw lighting in the unmasked areas
5109 R_Shadow_RenderMode_Lighting(false, false, false, false);
5111 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5112 for (i = 0;i < numlightentities;i++)
5113 R_Shadow_DrawEntityLight(lightentities[i]);
5114 for (i = 0;i < numlightentities_noselfshadow;i++)
5115 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5117 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5118 if (r_shadow_usingdeferredprepass)
5119 R_Shadow_RenderMode_DrawDeferredLight(false);
5123 static void R_Shadow_FreeDeferred(void)
5125 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
5126 r_shadow_prepassgeometryfbo = 0;
5128 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
5129 r_shadow_prepasslightingdiffusespecularfbo = 0;
5131 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
5132 r_shadow_prepasslightingdiffusefbo = 0;
5134 if (r_shadow_prepassgeometrydepthbuffer)
5135 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
5136 r_shadow_prepassgeometrydepthbuffer = NULL;
5138 if (r_shadow_prepassgeometrynormalmaptexture)
5139 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
5140 r_shadow_prepassgeometrynormalmaptexture = NULL;
5142 if (r_shadow_prepasslightingdiffusetexture)
5143 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
5144 r_shadow_prepasslightingdiffusetexture = NULL;
5146 if (r_shadow_prepasslightingspeculartexture)
5147 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
5148 r_shadow_prepasslightingspeculartexture = NULL;
5151 void R_Shadow_DrawPrepass(void)
5155 entity_render_t *ent;
5156 float clearcolor[4];
5158 R_Mesh_ResetTextureState();
5160 GL_ColorMask(1,1,1,1);
5161 GL_BlendFunc(GL_ONE, GL_ZERO);
5164 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5165 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
5166 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
5167 if (r_timereport_active)
5168 R_TimeReport("prepasscleargeom");
5170 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
5171 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
5172 if (r_timereport_active)
5173 R_TimeReport("prepassworld");
5175 for (i = 0;i < r_refdef.scene.numentities;i++)
5177 if (!r_refdef.viewcache.entityvisible[i])
5179 ent = r_refdef.scene.entities[i];
5180 if (ent->model && ent->model->DrawPrepass != NULL)
5181 ent->model->DrawPrepass(ent);
5184 if (r_timereport_active)
5185 R_TimeReport("prepassmodels");
5187 GL_DepthMask(false);
5188 GL_ColorMask(1,1,1,1);
5191 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5192 Vector4Set(clearcolor, 0, 0, 0, 0);
5193 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
5194 if (r_timereport_active)
5195 R_TimeReport("prepassclearlit");
5197 R_Shadow_RenderMode_Begin();
5199 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5200 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5202 R_Shadow_RenderMode_End();
5204 if (r_timereport_active)
5205 R_TimeReport("prepasslights");
5208 #define MAX_SCENELIGHTS 65536
5209 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
5211 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
5213 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
5215 r_shadow_scenemaxlights *= 2;
5216 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
5217 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
5219 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
5223 void R_Shadow_DrawLightSprites(void);
5224 void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
5233 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
5234 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
5235 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
5237 if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
5238 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
5239 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
5240 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
5241 r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) ||
5242 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
5243 r_shadow_shadowmapborder != shadowmapborder ||
5244 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
5245 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
5246 R_Shadow_FreeShadowMaps();
5248 r_shadow_fb_fbo = fbo;
5249 r_shadow_fb_depthtexture = depthtexture;
5250 r_shadow_fb_colortexture = colortexture;
5252 r_shadow_usingshadowmaportho = false;
5254 switch (vid.renderpath)
5256 case RENDERPATH_GL20:
5257 case RENDERPATH_D3D9:
5258 case RENDERPATH_D3D10:
5259 case RENDERPATH_D3D11:
5260 case RENDERPATH_SOFT:
5262 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
5264 r_shadow_usingdeferredprepass = false;
5265 if (r_shadow_prepass_width)
5266 R_Shadow_FreeDeferred();
5267 r_shadow_prepass_width = r_shadow_prepass_height = 0;
5271 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
5273 R_Shadow_FreeDeferred();
5275 r_shadow_usingdeferredprepass = true;
5276 r_shadow_prepass_width = vid.width;
5277 r_shadow_prepass_height = vid.height;
5278 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
5279 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);
5280 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);
5281 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);
5283 // set up the geometry pass fbo (depth + normalmap)
5284 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5285 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5286 // render depth into a renderbuffer and other important properties into the normalmap texture
5288 // set up the lighting pass fbo (diffuse + specular)
5289 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5290 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5291 // render diffuse into one texture and specular into another,
5292 // with depth and normalmap bound as textures,
5293 // with depth bound as attachment as well
5295 // set up the lighting pass fbo (diffuse)
5296 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5297 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5298 // render diffuse into one texture,
5299 // with depth and normalmap bound as textures,
5300 // with depth bound as attachment as well
5304 case RENDERPATH_GL11:
5305 case RENDERPATH_GL13:
5306 case RENDERPATH_GLES1:
5307 case RENDERPATH_GLES2:
5308 r_shadow_usingdeferredprepass = false;
5312 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);
5314 r_shadow_scenenumlights = 0;
5315 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5316 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5317 for (lightindex = 0; lightindex < range; lightindex++)
5319 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5320 if (light && (light->flags & flag))
5322 R_Shadow_PrepareLight(&light->rtlight);
5323 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5326 if (r_refdef.scene.rtdlight)
5328 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5330 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
5331 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
5334 else if (gl_flashblend.integer)
5336 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5338 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
5339 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
5340 VectorScale(rtlight->color, f, rtlight->currentcolor);
5344 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
5345 if (r_shadow_debuglight.integer >= 0)
5347 r_shadow_scenenumlights = 0;
5348 lightindex = r_shadow_debuglight.integer;
5349 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5352 R_Shadow_PrepareLight(&light->rtlight);
5353 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5357 // if we're doing shadowmaps we need to prepare the atlas layout now
5358 if (R_Shadow_ShadowMappingEnabled())
5362 // allocate shadowmaps in the atlas now
5363 // 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...
5364 for (lod = 0; lod < 16; lod++)
5366 int packing_success = 0;
5367 int packing_failure = 0;
5368 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
5369 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
5370 if (r_shadow_shadowmapatlas_modelshadows_size)
5371 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);
5372 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5374 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
5375 int size = rtlight->shadowmapsidesize >> lod;
5377 if (!rtlight->castshadows)
5379 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
5382 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
5383 if (rtlight->cached_numshadowentities_noselfshadow)
5385 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
5387 rtlight->shadowmapatlassidesize = size;
5392 // note down that we failed to pack this one, it will have to disable shadows
5393 rtlight->shadowmapatlassidesize = 0;
5397 // generally everything fits and we stop here on the first iteration
5398 if (packing_failure == 0)
5403 if (r_editlights.integer)
5404 R_Shadow_DrawLightSprites();
5407 void R_Shadow_DrawShadowMaps(void)
5409 R_Shadow_RenderMode_Begin();
5410 R_Shadow_RenderMode_ActiveLight(NULL);
5412 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
5413 R_Shadow_ClearShadowMapTexture();
5415 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
5416 if (r_shadow_shadowmapatlas_modelshadows_size)
5418 R_Shadow_DrawModelShadowMaps();
5419 // don't let sound skip if going slow
5420 if (r_refdef.scene.extraupdate)
5424 if (R_Shadow_ShadowMappingEnabled())
5427 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5428 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
5431 R_Shadow_RenderMode_End();
5434 void R_Shadow_DrawLights(void)
5438 R_Shadow_RenderMode_Begin();
5440 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5441 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5443 R_Shadow_RenderMode_End();
5446 #define MAX_MODELSHADOWS 1024
5447 static int r_shadow_nummodelshadows;
5448 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
5450 void R_Shadow_PrepareModelShadows(void)
5453 float scale, size, radius, dot1, dot2;
5454 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5455 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
5456 entity_render_t *ent;
5458 r_shadow_nummodelshadows = 0;
5459 r_shadow_shadowmapatlas_modelshadows_size = 0;
5461 if (!r_refdef.scene.numentities || r_refdef.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
5464 switch (r_shadow_shadowmode)
5466 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
5467 if (r_shadows.integer >= 2)
5470 case R_SHADOW_SHADOWMODE_STENCIL:
5473 for (i = 0; i < r_refdef.scene.numentities; i++)
5475 ent = r_refdef.scene.entities[i];
5476 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5478 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5480 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5481 R_AnimCache_GetEntity(ent, false, false);
5489 size = 2 * r_shadow_shadowmapmaxsize;
5490 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
5491 radius = 0.5f * size / scale;
5493 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5494 VectorCopy(prvmshadowdir, shadowdir);
5495 VectorNormalize(shadowdir);
5496 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5497 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5498 if (fabs(dot1) <= fabs(dot2))
5499 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5501 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5502 VectorNormalize(shadowforward);
5503 CrossProduct(shadowdir, shadowforward, shadowright);
5504 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5505 VectorCopy(prvmshadowfocus, shadowfocus);
5506 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5507 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5508 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5509 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5510 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5512 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5514 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5515 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5516 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5517 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5518 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5519 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5521 for (i = 0; i < r_refdef.scene.numentities; i++)
5523 ent = r_refdef.scene.entities[i];
5524 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
5526 // cast shadows from anything of the map (submodels are optional)
5527 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5529 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5531 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5532 R_AnimCache_GetEntity(ent, false, false);
5536 if (r_shadow_nummodelshadows)
5538 r_shadow_shadowmapatlas_modelshadows_x = 0;
5539 r_shadow_shadowmapatlas_modelshadows_y = 0;
5540 r_shadow_shadowmapatlas_modelshadows_size = size;
5544 static void R_Shadow_DrawModelShadowMaps(void)
5547 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
5548 entity_render_t *ent;
5549 vec3_t relativelightorigin;
5550 vec3_t relativelightdirection, relativeforward, relativeright;
5551 vec3_t relativeshadowmins, relativeshadowmaxs;
5552 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
5553 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5555 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
5556 r_viewport_t viewport;
5558 size = r_shadow_shadowmapatlas_modelshadows_size;
5559 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
5560 radius = 0.5f / scale;
5561 nearclip = -r_shadows_throwdistance.value;
5562 farclip = r_shadows_throwdistance.value;
5563 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);
5565 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
5566 r_shadow_modelshadowmap_parameters[0] = size;
5567 r_shadow_modelshadowmap_parameters[1] = size;
5568 r_shadow_modelshadowmap_parameters[2] = 1.0;
5569 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
5570 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
5571 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
5572 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
5573 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
5574 r_shadow_usingshadowmaportho = true;
5576 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5577 VectorCopy(prvmshadowdir, shadowdir);
5578 VectorNormalize(shadowdir);
5579 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5580 VectorCopy(prvmshadowfocus, shadowfocus);
5581 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5582 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5583 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5584 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5585 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5586 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5587 if (fabs(dot1) <= fabs(dot2))
5588 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5590 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5591 VectorNormalize(shadowforward);
5592 VectorM(scale, shadowforward, &m[0]);
5593 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5595 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
5596 CrossProduct(shadowdir, shadowforward, shadowright);
5597 VectorM(scale, shadowright, &m[4]);
5598 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
5599 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
5600 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
5601 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
5602 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
5603 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);
5604 R_SetViewport(&viewport);
5606 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5608 // render into a slightly restricted region so that the borders of the
5609 // shadowmap area fade away, rather than streaking across everything
5610 // outside the usable area
5611 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
5613 for (i = 0;i < r_shadow_nummodelshadows;i++)
5615 ent = r_shadow_modelshadows[i];
5616 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5617 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
5618 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5619 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
5620 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
5621 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5622 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5623 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5624 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5625 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5626 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5627 RSurf_ActiveModelEntity(ent, false, false, false);
5628 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
5629 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5635 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
5637 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
5639 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
5640 Cvar_SetValueQuick(&r_test, 0);
5645 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
5646 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
5647 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
5648 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
5649 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
5650 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
5652 switch (vid.renderpath)
5654 case RENDERPATH_GL11:
5655 case RENDERPATH_GL13:
5656 case RENDERPATH_GL20:
5657 case RENDERPATH_SOFT:
5658 case RENDERPATH_GLES1:
5659 case RENDERPATH_GLES2:
5661 case RENDERPATH_D3D9:
5662 case RENDERPATH_D3D10:
5663 case RENDERPATH_D3D11:
5664 #ifdef MATRIX4x4_OPENGLORIENTATION
5665 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5666 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
5667 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
5668 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
5670 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5671 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
5672 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
5673 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
5679 void R_Shadow_DrawModelShadows(void)
5682 float relativethrowdistance;
5683 entity_render_t *ent;
5684 vec3_t relativelightorigin;
5685 vec3_t relativelightdirection;
5686 vec3_t relativeshadowmins, relativeshadowmaxs;
5687 vec3_t tmp, shadowdir;
5688 prvm_vec3_t prvmshadowdir;
5690 if (!r_shadow_nummodelshadows || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
5693 R_ResetViewRendering3D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5694 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
5695 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5696 R_Shadow_RenderMode_Begin();
5697 R_Shadow_RenderMode_ActiveLight(NULL);
5698 r_shadow_lightscissor[0] = r_refdef.view.x;
5699 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
5700 r_shadow_lightscissor[2] = r_refdef.view.width;
5701 r_shadow_lightscissor[3] = r_refdef.view.height;
5702 R_Shadow_RenderMode_StencilShadowVolumes(false);
5705 if (r_shadows.integer == 2)
5707 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5708 VectorCopy(prvmshadowdir, shadowdir);
5709 VectorNormalize(shadowdir);
5712 R_Shadow_ClearStencil();
5714 for (i = 0;i < r_shadow_nummodelshadows;i++)
5716 ent = r_shadow_modelshadows[i];
5718 // cast shadows from anything of the map (submodels are optional)
5719 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5720 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
5721 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
5722 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
5723 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5726 if(ent->entitynumber != 0)
5728 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
5730 // FIXME handle this
5731 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5735 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
5736 int entnum, entnum2, recursion;
5737 entnum = entnum2 = ent->entitynumber;
5738 for(recursion = 32; recursion > 0; --recursion)
5740 entnum2 = cl.entities[entnum].state_current.tagentity;
5741 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
5746 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
5748 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
5749 // transform into modelspace of OUR entity
5750 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
5751 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
5754 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5758 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5761 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
5762 RSurf_ActiveModelEntity(ent, false, false, false);
5763 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
5764 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5767 // not really the right mode, but this will disable any silly stencil features
5768 R_Shadow_RenderMode_End();
5770 // set up ortho view for rendering this pass
5771 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5772 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5773 //GL_ScissorTest(true);
5774 //R_EntityMatrix(&identitymatrix);
5775 //R_Mesh_ResetTextureState();
5776 R_ResetViewRendering2D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5778 // set up a darkening blend on shadowed areas
5779 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5780 //GL_DepthRange(0, 1);
5781 //GL_DepthTest(false);
5782 //GL_DepthMask(false);
5783 //GL_PolygonOffset(0, 0);CHECKGLERROR
5784 GL_Color(0, 0, 0, r_shadows_darken.value);
5785 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5786 //GL_DepthFunc(GL_ALWAYS);
5787 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5789 // apply the blend to the shadowed areas
5790 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5791 R_SetupShader_Generic_NoTexture(false, true);
5792 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5794 // restore the viewport
5795 R_SetViewport(&r_refdef.view.viewport);
5797 // restore other state to normal
5798 //R_Shadow_RenderMode_End();
5801 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5804 vec3_t centerorigin;
5805 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5808 // if it's too close, skip it
5809 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5811 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5814 if (usequery && r_numqueries + 2 <= r_maxqueries)
5816 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5817 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5818 // 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
5819 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5821 switch(vid.renderpath)
5823 case RENDERPATH_GL11:
5824 case RENDERPATH_GL13:
5825 case RENDERPATH_GL20:
5826 case RENDERPATH_GLES1:
5827 case RENDERPATH_GLES2:
5828 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5830 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5831 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5832 GL_DepthFunc(GL_ALWAYS);
5833 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5834 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5835 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5836 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5837 GL_DepthFunc(GL_LEQUAL);
5838 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5839 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5840 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5841 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5842 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5846 case RENDERPATH_D3D9:
5847 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5849 case RENDERPATH_D3D10:
5850 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5852 case RENDERPATH_D3D11:
5853 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5855 case RENDERPATH_SOFT:
5856 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5860 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5863 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5865 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5868 unsigned int occlude = 0;
5869 GLint allpixels = 0, visiblepixels = 0;
5871 // now we have to check the query result
5872 if (rtlight->corona_queryindex_visiblepixels)
5874 switch(vid.renderpath)
5876 case RENDERPATH_GL11:
5877 case RENDERPATH_GL13:
5878 case RENDERPATH_GL20:
5879 case RENDERPATH_GLES1:
5880 case RENDERPATH_GLES2:
5881 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5883 // See if we can use the GPU-side method to prevent implicit sync
5884 if (vid.support.arb_query_buffer_object) {
5885 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
5886 if (!r_shadow_occlusion_buf) {
5887 qglGenBuffersARB(1, &r_shadow_occlusion_buf);
5888 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5889 qglBufferDataARB(GL_QUERY_BUFFER_ARB, 8, NULL, GL_DYNAMIC_COPY);
5891 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5893 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(0));
5894 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4));
5895 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
5896 occlude = MATERIALFLAG_OCCLUDE;
5898 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5899 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5900 if (visiblepixels < 1 || allpixels < 1)
5902 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5904 cscale *= rtlight->corona_visibility;
5910 case RENDERPATH_D3D9:
5911 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5913 case RENDERPATH_D3D10:
5914 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5916 case RENDERPATH_D3D11:
5917 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5919 case RENDERPATH_SOFT:
5920 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5928 // FIXME: these traces should scan all render entities instead of cl.world
5929 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)
5932 VectorScale(rtlight->currentcolor, cscale, color);
5933 if (VectorLength(color) > (1.0f / 256.0f))
5936 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
5939 VectorNegate(color, color);
5940 GL_BlendEquationSubtract(true);
5942 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5943 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);
5944 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
5946 GL_BlendEquationSubtract(false);
5950 void R_Shadow_DrawCoronas(void)
5953 qboolean usequery = false;
5958 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
5960 if (r_fb.water.renderingscene)
5962 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5963 R_EntityMatrix(&identitymatrix);
5965 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5967 // check occlusion of coronas
5968 // use GL_ARB_occlusion_query if available
5969 // otherwise use raytraces
5971 switch (vid.renderpath)
5973 case RENDERPATH_GL11:
5974 case RENDERPATH_GL13:
5975 case RENDERPATH_GL20:
5976 case RENDERPATH_GLES1:
5977 case RENDERPATH_GLES2:
5978 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
5979 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5982 GL_ColorMask(0,0,0,0);
5983 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
5984 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
5987 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
5988 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
5990 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
5993 RSurf_ActiveWorldEntity();
5994 GL_BlendFunc(GL_ONE, GL_ZERO);
5995 GL_CullFace(GL_NONE);
5996 GL_DepthMask(false);
5997 GL_DepthRange(0, 1);
5998 GL_PolygonOffset(0, 0);
6000 R_Mesh_ResetTextureState();
6001 R_SetupShader_Generic_NoTexture(false, false);
6005 case RENDERPATH_D3D9:
6007 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6009 case RENDERPATH_D3D10:
6010 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6012 case RENDERPATH_D3D11:
6013 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6015 case RENDERPATH_SOFT:
6017 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6020 for (lightindex = 0;lightindex < range;lightindex++)
6022 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6025 rtlight = &light->rtlight;
6026 rtlight->corona_visibility = 0;
6027 rtlight->corona_queryindex_visiblepixels = 0;
6028 rtlight->corona_queryindex_allpixels = 0;
6029 if (!(rtlight->flags & flag))
6031 if (rtlight->corona <= 0)
6033 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
6035 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6037 for (i = 0;i < r_refdef.scene.numlights;i++)
6039 rtlight = r_refdef.scene.lights[i];
6040 rtlight->corona_visibility = 0;
6041 rtlight->corona_queryindex_visiblepixels = 0;
6042 rtlight->corona_queryindex_allpixels = 0;
6043 if (!(rtlight->flags & flag))
6045 if (rtlight->corona <= 0)
6047 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6050 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
6052 // now draw the coronas using the query data for intensity info
6053 for (lightindex = 0;lightindex < range;lightindex++)
6055 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6058 rtlight = &light->rtlight;
6059 if (rtlight->corona_visibility <= 0)
6061 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6063 for (i = 0;i < r_refdef.scene.numlights;i++)
6065 rtlight = r_refdef.scene.lights[i];
6066 if (rtlight->corona_visibility <= 0)
6068 if (gl_flashblend.integer)
6069 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
6071 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6077 static dlight_t *R_Shadow_NewWorldLight(void)
6079 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
6082 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)
6086 // 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
6088 // validate parameters
6092 // copy to light properties
6093 VectorCopy(origin, light->origin);
6094 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
6095 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
6096 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
6098 light->color[0] = max(color[0], 0);
6099 light->color[1] = max(color[1], 0);
6100 light->color[2] = max(color[2], 0);
6102 light->color[0] = color[0];
6103 light->color[1] = color[1];
6104 light->color[2] = color[2];
6105 light->radius = max(radius, 0);
6106 light->style = style;
6107 light->shadow = shadowenable;
6108 light->corona = corona;
6109 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
6110 light->coronasizescale = coronasizescale;
6111 light->ambientscale = ambientscale;
6112 light->diffusescale = diffusescale;
6113 light->specularscale = specularscale;
6114 light->flags = flags;
6116 // update renderable light data
6117 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
6118 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);
6121 static void R_Shadow_FreeWorldLight(dlight_t *light)
6123 if (r_shadow_selectedlight == light)
6124 r_shadow_selectedlight = NULL;
6125 R_RTLight_Uncompile(&light->rtlight);
6126 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
6129 void R_Shadow_ClearWorldLights(void)
6133 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6134 for (lightindex = 0;lightindex < range;lightindex++)
6136 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6138 R_Shadow_FreeWorldLight(light);
6140 r_shadow_selectedlight = NULL;
6143 static void R_Shadow_SelectLight(dlight_t *light)
6145 if (r_shadow_selectedlight)
6146 r_shadow_selectedlight->selected = false;
6147 r_shadow_selectedlight = light;
6148 if (r_shadow_selectedlight)
6149 r_shadow_selectedlight->selected = true;
6152 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6154 // this is never batched (there can be only one)
6156 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
6157 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6158 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6161 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6166 skinframe_t *skinframe;
6169 // this is never batched (due to the ent parameter changing every time)
6170 // so numsurfaces == 1 and surfacelist[0] == lightnumber
6171 const dlight_t *light = (dlight_t *)ent;
6174 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
6177 VectorScale(light->color, intensity, spritecolor);
6178 if (VectorLength(spritecolor) < 0.1732f)
6179 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
6180 if (VectorLength(spritecolor) > 1.0f)
6181 VectorNormalize(spritecolor);
6183 // draw light sprite
6184 if (light->cubemapname[0] && !light->shadow)
6185 skinframe = r_editlights_sprcubemapnoshadowlight;
6186 else if (light->cubemapname[0])
6187 skinframe = r_editlights_sprcubemaplight;
6188 else if (!light->shadow)
6189 skinframe = r_editlights_sprnoshadowlight;
6191 skinframe = r_editlights_sprlight;
6193 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);
6194 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6196 // draw selection sprite if light is selected
6197 if (light->selected)
6199 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6200 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6201 // VorteX todo: add normalmode/realtime mode light overlay sprites?
6205 void R_Shadow_DrawLightSprites(void)
6209 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6210 for (lightindex = 0;lightindex < range;lightindex++)
6212 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6214 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
6216 if (!r_editlights_lockcursor)
6217 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
6220 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
6225 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6226 if (lightindex >= range)
6228 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6231 rtlight = &light->rtlight;
6232 //if (!(rtlight->flags & flag))
6234 VectorCopy(rtlight->shadoworigin, origin);
6235 *radius = rtlight->radius;
6236 VectorCopy(rtlight->color, color);
6240 static void R_Shadow_SelectLightInView(void)
6242 float bestrating, rating, temp[3];
6246 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6250 if (r_editlights_lockcursor)
6252 for (lightindex = 0;lightindex < range;lightindex++)
6254 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6257 VectorSubtract(light->origin, r_refdef.view.origin, temp);
6258 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
6261 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
6262 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)
6264 bestrating = rating;
6269 R_Shadow_SelectLight(best);
6272 void R_Shadow_LoadWorldLights(void)
6274 int n, a, style, shadow, flags;
6275 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
6276 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
6277 if (cl.worldmodel == NULL)
6279 Con_Print("No map loaded.\n");
6282 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6283 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6293 for (;COM_Parse(t, true) && strcmp(
6294 if (COM_Parse(t, true))
6296 if (com_token[0] == '!')
6299 origin[0] = atof(com_token+1);
6302 origin[0] = atof(com_token);
6307 while (*s && *s != '\n' && *s != '\r')
6313 // check for modifier flags
6320 #if _MSC_VER >= 1400
6321 #define sscanf sscanf_s
6323 cubemapname[sizeof(cubemapname)-1] = 0;
6324 #if MAX_QPATH != 128
6325 #error update this code if MAX_QPATH changes
6327 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
6328 #if _MSC_VER >= 1400
6329 , sizeof(cubemapname)
6331 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
6334 flags = LIGHTFLAG_REALTIMEMODE;
6342 coronasizescale = 0.25f;
6344 VectorClear(angles);
6347 if (a < 9 || !strcmp(cubemapname, "\"\""))
6349 // remove quotes on cubemapname
6350 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
6353 namelen = strlen(cubemapname) - 2;
6354 memmove(cubemapname, cubemapname + 1, namelen);
6355 cubemapname[namelen] = '\0';
6359 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);
6362 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6370 Con_Printf("invalid rtlights file \"%s\"\n", name);
6371 Mem_Free(lightsstring);
6375 void R_Shadow_SaveWorldLights(void)
6379 size_t bufchars, bufmaxchars;
6381 char name[MAX_QPATH];
6382 char line[MAX_INPUTLINE];
6383 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
6384 // I hate lines which are 3 times my screen size :( --blub
6387 if (cl.worldmodel == NULL)
6389 Con_Print("No map loaded.\n");
6392 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6393 bufchars = bufmaxchars = 0;
6395 for (lightindex = 0;lightindex < range;lightindex++)
6397 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6400 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
6401 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);
6402 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
6403 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]);
6405 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);
6406 if (bufchars + strlen(line) > bufmaxchars)
6408 bufmaxchars = bufchars + strlen(line) + 2048;
6410 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
6414 memcpy(buf, oldbuf, bufchars);
6420 memcpy(buf + bufchars, line, strlen(line));
6421 bufchars += strlen(line);
6425 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
6430 void R_Shadow_LoadLightsFile(void)
6433 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
6434 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
6435 if (cl.worldmodel == NULL)
6437 Con_Print("No map loaded.\n");
6440 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
6441 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6449 while (*s && *s != '\n' && *s != '\r')
6455 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);
6459 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);
6462 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
6463 radius = bound(15, radius, 4096);
6464 VectorScale(color, (2.0f / (8388608.0f)), color);
6465 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6473 Con_Printf("invalid lights file \"%s\"\n", name);
6474 Mem_Free(lightsstring);
6478 // tyrlite/hmap2 light types in the delay field
6479 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
6481 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
6493 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
6494 char key[256], value[MAX_INPUTLINE];
6497 if (cl.worldmodel == NULL)
6499 Con_Print("No map loaded.\n");
6502 // try to load a .ent file first
6503 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
6504 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
6505 // and if that is not found, fall back to the bsp file entity string
6507 data = cl.worldmodel->brush.entities;
6510 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
6512 type = LIGHTTYPE_MINUSX;
6513 origin[0] = origin[1] = origin[2] = 0;
6514 originhack[0] = originhack[1] = originhack[2] = 0;
6515 angles[0] = angles[1] = angles[2] = 0;
6516 color[0] = color[1] = color[2] = 1;
6517 light[0] = light[1] = light[2] = 1;light[3] = 300;
6518 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
6528 if (!COM_ParseToken_Simple(&data, false, false, true))
6530 if (com_token[0] == '}')
6531 break; // end of entity
6532 if (com_token[0] == '_')
6533 strlcpy(key, com_token + 1, sizeof(key));
6535 strlcpy(key, com_token, sizeof(key));
6536 while (key[strlen(key)-1] == ' ') // remove trailing spaces
6537 key[strlen(key)-1] = 0;
6538 if (!COM_ParseToken_Simple(&data, false, false, true))
6540 strlcpy(value, com_token, sizeof(value));
6542 // now that we have the key pair worked out...
6543 if (!strcmp("light", key))
6545 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
6549 light[0] = vec[0] * (1.0f / 256.0f);
6550 light[1] = vec[0] * (1.0f / 256.0f);
6551 light[2] = vec[0] * (1.0f / 256.0f);
6557 light[0] = vec[0] * (1.0f / 255.0f);
6558 light[1] = vec[1] * (1.0f / 255.0f);
6559 light[2] = vec[2] * (1.0f / 255.0f);
6563 else if (!strcmp("delay", key))
6565 else if (!strcmp("origin", key))
6566 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
6567 else if (!strcmp("angle", key))
6568 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
6569 else if (!strcmp("angles", key))
6570 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
6571 else if (!strcmp("color", key))
6572 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
6573 else if (!strcmp("wait", key))
6574 fadescale = atof(value);
6575 else if (!strcmp("classname", key))
6577 if (!strncmp(value, "light", 5))
6580 if (!strcmp(value, "light_fluoro"))
6585 overridecolor[0] = 1;
6586 overridecolor[1] = 1;
6587 overridecolor[2] = 1;
6589 if (!strcmp(value, "light_fluorospark"))
6594 overridecolor[0] = 1;
6595 overridecolor[1] = 1;
6596 overridecolor[2] = 1;
6598 if (!strcmp(value, "light_globe"))
6603 overridecolor[0] = 1;
6604 overridecolor[1] = 0.8;
6605 overridecolor[2] = 0.4;
6607 if (!strcmp(value, "light_flame_large_yellow"))
6612 overridecolor[0] = 1;
6613 overridecolor[1] = 0.5;
6614 overridecolor[2] = 0.1;
6616 if (!strcmp(value, "light_flame_small_yellow"))
6621 overridecolor[0] = 1;
6622 overridecolor[1] = 0.5;
6623 overridecolor[2] = 0.1;
6625 if (!strcmp(value, "light_torch_small_white"))
6630 overridecolor[0] = 1;
6631 overridecolor[1] = 0.5;
6632 overridecolor[2] = 0.1;
6634 if (!strcmp(value, "light_torch_small_walltorch"))
6639 overridecolor[0] = 1;
6640 overridecolor[1] = 0.5;
6641 overridecolor[2] = 0.1;
6645 else if (!strcmp("style", key))
6646 style = atoi(value);
6647 else if (!strcmp("skin", key))
6648 skin = (int)atof(value);
6649 else if (!strcmp("pflags", key))
6650 pflags = (int)atof(value);
6651 //else if (!strcmp("effects", key))
6652 // effects = (int)atof(value);
6653 else if (cl.worldmodel->type == mod_brushq3)
6655 if (!strcmp("scale", key))
6656 lightscale = atof(value);
6657 if (!strcmp("fade", key))
6658 fadescale = atof(value);
6663 if (lightscale <= 0)
6667 if (color[0] == color[1] && color[0] == color[2])
6669 color[0] *= overridecolor[0];
6670 color[1] *= overridecolor[1];
6671 color[2] *= overridecolor[2];
6673 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
6674 color[0] = color[0] * light[0];
6675 color[1] = color[1] * light[1];
6676 color[2] = color[2] * light[2];
6679 case LIGHTTYPE_MINUSX:
6681 case LIGHTTYPE_RECIPX:
6683 VectorScale(color, (1.0f / 16.0f), color);
6685 case LIGHTTYPE_RECIPXX:
6687 VectorScale(color, (1.0f / 16.0f), color);
6690 case LIGHTTYPE_NONE:
6694 case LIGHTTYPE_MINUSXX:
6697 VectorAdd(origin, originhack, origin);
6699 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);
6702 Mem_Free(entfiledata);
6706 static void R_Shadow_SetCursorLocationForView(void)
6709 vec3_t dest, endpos;
6711 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
6712 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true);
6713 if (trace.fraction < 1)
6715 dist = trace.fraction * r_editlights_cursordistance.value;
6716 push = r_editlights_cursorpushback.value;
6720 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
6721 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
6725 VectorClear( endpos );
6727 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6728 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6729 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6732 void R_Shadow_UpdateWorldLightSelection(void)
6734 if (r_editlights.integer)
6736 R_Shadow_SetCursorLocationForView();
6737 R_Shadow_SelectLightInView();
6740 R_Shadow_SelectLight(NULL);
6743 static void R_Shadow_EditLights_Clear_f(void)
6745 R_Shadow_ClearWorldLights();
6748 void R_Shadow_EditLights_Reload_f(void)
6752 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
6753 R_Shadow_ClearWorldLights();
6754 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
6756 R_Shadow_LoadWorldLights();
6757 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6758 R_Shadow_LoadLightsFile();
6760 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
6762 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6763 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6767 static void R_Shadow_EditLights_Save_f(void)
6771 R_Shadow_SaveWorldLights();
6774 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6776 R_Shadow_ClearWorldLights();
6777 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6780 static void R_Shadow_EditLights_ImportLightsFile_f(void)
6782 R_Shadow_ClearWorldLights();
6783 R_Shadow_LoadLightsFile();
6786 static void R_Shadow_EditLights_Spawn_f(void)
6789 if (!r_editlights.integer)
6791 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6794 if (Cmd_Argc() != 1)
6796 Con_Print("r_editlights_spawn does not take parameters\n");
6799 color[0] = color[1] = color[2] = 1;
6800 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6803 static void R_Shadow_EditLights_Edit_f(void)
6805 vec3_t origin, angles, color;
6806 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6807 int style, shadows, flags, normalmode, realtimemode;
6808 char cubemapname[MAX_INPUTLINE];
6809 if (!r_editlights.integer)
6811 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6814 if (!r_shadow_selectedlight)
6816 Con_Print("No selected light.\n");
6819 VectorCopy(r_shadow_selectedlight->origin, origin);
6820 VectorCopy(r_shadow_selectedlight->angles, angles);
6821 VectorCopy(r_shadow_selectedlight->color, color);
6822 radius = r_shadow_selectedlight->radius;
6823 style = r_shadow_selectedlight->style;
6824 if (r_shadow_selectedlight->cubemapname)
6825 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6828 shadows = r_shadow_selectedlight->shadow;
6829 corona = r_shadow_selectedlight->corona;
6830 coronasizescale = r_shadow_selectedlight->coronasizescale;
6831 ambientscale = r_shadow_selectedlight->ambientscale;
6832 diffusescale = r_shadow_selectedlight->diffusescale;
6833 specularscale = r_shadow_selectedlight->specularscale;
6834 flags = r_shadow_selectedlight->flags;
6835 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6836 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6837 if (!strcmp(Cmd_Argv(1), "origin"))
6839 if (Cmd_Argc() != 5)
6841 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6844 origin[0] = atof(Cmd_Argv(2));
6845 origin[1] = atof(Cmd_Argv(3));
6846 origin[2] = atof(Cmd_Argv(4));
6848 else if (!strcmp(Cmd_Argv(1), "originscale"))
6850 if (Cmd_Argc() != 5)
6852 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6855 origin[0] *= atof(Cmd_Argv(2));
6856 origin[1] *= atof(Cmd_Argv(3));
6857 origin[2] *= atof(Cmd_Argv(4));
6859 else if (!strcmp(Cmd_Argv(1), "originx"))
6861 if (Cmd_Argc() != 3)
6863 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6866 origin[0] = atof(Cmd_Argv(2));
6868 else if (!strcmp(Cmd_Argv(1), "originy"))
6870 if (Cmd_Argc() != 3)
6872 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6875 origin[1] = atof(Cmd_Argv(2));
6877 else if (!strcmp(Cmd_Argv(1), "originz"))
6879 if (Cmd_Argc() != 3)
6881 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6884 origin[2] = atof(Cmd_Argv(2));
6886 else if (!strcmp(Cmd_Argv(1), "move"))
6888 if (Cmd_Argc() != 5)
6890 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6893 origin[0] += atof(Cmd_Argv(2));
6894 origin[1] += atof(Cmd_Argv(3));
6895 origin[2] += atof(Cmd_Argv(4));
6897 else if (!strcmp(Cmd_Argv(1), "movex"))
6899 if (Cmd_Argc() != 3)
6901 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6904 origin[0] += atof(Cmd_Argv(2));
6906 else if (!strcmp(Cmd_Argv(1), "movey"))
6908 if (Cmd_Argc() != 3)
6910 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6913 origin[1] += atof(Cmd_Argv(2));
6915 else if (!strcmp(Cmd_Argv(1), "movez"))
6917 if (Cmd_Argc() != 3)
6919 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6922 origin[2] += atof(Cmd_Argv(2));
6924 else if (!strcmp(Cmd_Argv(1), "angles"))
6926 if (Cmd_Argc() != 5)
6928 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6931 angles[0] = atof(Cmd_Argv(2));
6932 angles[1] = atof(Cmd_Argv(3));
6933 angles[2] = atof(Cmd_Argv(4));
6935 else if (!strcmp(Cmd_Argv(1), "anglesx"))
6937 if (Cmd_Argc() != 3)
6939 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6942 angles[0] = atof(Cmd_Argv(2));
6944 else if (!strcmp(Cmd_Argv(1), "anglesy"))
6946 if (Cmd_Argc() != 3)
6948 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6951 angles[1] = atof(Cmd_Argv(2));
6953 else if (!strcmp(Cmd_Argv(1), "anglesz"))
6955 if (Cmd_Argc() != 3)
6957 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6960 angles[2] = atof(Cmd_Argv(2));
6962 else if (!strcmp(Cmd_Argv(1), "color"))
6964 if (Cmd_Argc() != 5)
6966 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
6969 color[0] = atof(Cmd_Argv(2));
6970 color[1] = atof(Cmd_Argv(3));
6971 color[2] = atof(Cmd_Argv(4));
6973 else if (!strcmp(Cmd_Argv(1), "radius"))
6975 if (Cmd_Argc() != 3)
6977 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6980 radius = atof(Cmd_Argv(2));
6982 else if (!strcmp(Cmd_Argv(1), "colorscale"))
6984 if (Cmd_Argc() == 3)
6986 double scale = atof(Cmd_Argv(2));
6993 if (Cmd_Argc() != 5)
6995 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
6998 color[0] *= atof(Cmd_Argv(2));
6999 color[1] *= atof(Cmd_Argv(3));
7000 color[2] *= atof(Cmd_Argv(4));
7003 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
7005 if (Cmd_Argc() != 3)
7007 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7010 radius *= atof(Cmd_Argv(2));
7012 else if (!strcmp(Cmd_Argv(1), "style"))
7014 if (Cmd_Argc() != 3)
7016 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7019 style = atoi(Cmd_Argv(2));
7021 else if (!strcmp(Cmd_Argv(1), "cubemap"))
7025 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7028 if (Cmd_Argc() == 3)
7029 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
7033 else if (!strcmp(Cmd_Argv(1), "shadows"))
7035 if (Cmd_Argc() != 3)
7037 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7040 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7042 else if (!strcmp(Cmd_Argv(1), "corona"))
7044 if (Cmd_Argc() != 3)
7046 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7049 corona = atof(Cmd_Argv(2));
7051 else if (!strcmp(Cmd_Argv(1), "coronasize"))
7053 if (Cmd_Argc() != 3)
7055 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7058 coronasizescale = atof(Cmd_Argv(2));
7060 else if (!strcmp(Cmd_Argv(1), "ambient"))
7062 if (Cmd_Argc() != 3)
7064 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7067 ambientscale = atof(Cmd_Argv(2));
7069 else if (!strcmp(Cmd_Argv(1), "diffuse"))
7071 if (Cmd_Argc() != 3)
7073 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7076 diffusescale = atof(Cmd_Argv(2));
7078 else if (!strcmp(Cmd_Argv(1), "specular"))
7080 if (Cmd_Argc() != 3)
7082 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7085 specularscale = atof(Cmd_Argv(2));
7087 else if (!strcmp(Cmd_Argv(1), "normalmode"))
7089 if (Cmd_Argc() != 3)
7091 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7094 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7096 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
7098 if (Cmd_Argc() != 3)
7100 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7103 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7107 Con_Print("usage: r_editlights_edit [property] [value]\n");
7108 Con_Print("Selected light's properties:\n");
7109 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7110 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7111 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7112 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
7113 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
7114 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
7115 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
7116 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
7117 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
7118 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
7119 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
7120 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
7121 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
7122 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
7125 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
7126 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
7129 static void R_Shadow_EditLights_EditAll_f(void)
7132 dlight_t *light, *oldselected;
7135 if (!r_editlights.integer)
7137 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
7141 oldselected = r_shadow_selectedlight;
7142 // EditLights doesn't seem to have a "remove" command or something so:
7143 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7144 for (lightindex = 0;lightindex < range;lightindex++)
7146 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7149 R_Shadow_SelectLight(light);
7150 R_Shadow_EditLights_Edit_f();
7152 // return to old selected (to not mess editing once selection is locked)
7153 R_Shadow_SelectLight(oldselected);
7156 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
7158 int lightnumber, lightcount;
7159 size_t lightindex, range;
7164 if (!r_editlights.integer)
7167 // update cvars so QC can query them
7168 if (r_shadow_selectedlight)
7170 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7171 Cvar_SetQuick(&r_editlights_current_origin, temp);
7172 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7173 Cvar_SetQuick(&r_editlights_current_angles, temp);
7174 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7175 Cvar_SetQuick(&r_editlights_current_color, temp);
7176 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
7177 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
7178 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
7179 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
7180 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
7181 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
7182 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
7183 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
7184 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
7185 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
7186 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
7189 // draw properties on screen
7190 if (!r_editlights_drawproperties.integer)
7192 x = vid_conwidth.value - 320;
7194 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
7197 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7198 for (lightindex = 0;lightindex < range;lightindex++)
7200 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7203 if (light == r_shadow_selectedlight)
7204 lightnumber = (int)lightindex;
7207 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;
7208 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;
7210 if (r_shadow_selectedlight == NULL)
7212 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;
7213 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;
7214 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;
7215 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;
7216 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;
7217 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;
7218 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;
7219 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;
7220 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;
7221 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;
7222 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;
7223 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;
7224 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;
7225 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;
7226 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;
7228 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;
7229 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;
7230 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;
7231 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;
7232 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;
7233 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;
7234 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;
7235 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;
7236 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;
7237 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;
7240 static void R_Shadow_EditLights_ToggleShadow_f(void)
7242 if (!r_editlights.integer)
7244 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7247 if (!r_shadow_selectedlight)
7249 Con_Print("No selected light.\n");
7252 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);
7255 static void R_Shadow_EditLights_ToggleCorona_f(void)
7257 if (!r_editlights.integer)
7259 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7262 if (!r_shadow_selectedlight)
7264 Con_Print("No selected light.\n");
7267 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);
7270 static void R_Shadow_EditLights_Remove_f(void)
7272 if (!r_editlights.integer)
7274 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
7277 if (!r_shadow_selectedlight)
7279 Con_Print("No selected light.\n");
7282 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
7283 r_shadow_selectedlight = NULL;
7286 static void R_Shadow_EditLights_Help_f(void)
7289 "Documentation on r_editlights system:\n"
7291 "r_editlights : enable/disable editing mode\n"
7292 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
7293 "r_editlights_cursorpushback : push back cursor this far from surface\n"
7294 "r_editlights_cursorpushoff : push cursor off surface this far\n"
7295 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
7296 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
7298 "r_editlights_help : this help\n"
7299 "r_editlights_clear : remove all lights\n"
7300 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
7301 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
7302 "r_editlights_save : save to .rtlights file\n"
7303 "r_editlights_spawn : create a light with default settings\n"
7304 "r_editlights_edit command : edit selected light - more documentation below\n"
7305 "r_editlights_remove : remove selected light\n"
7306 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
7307 "r_editlights_importlightentitiesfrommap : reload light entities\n"
7308 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
7310 "origin x y z : set light location\n"
7311 "originx x: set x component of light location\n"
7312 "originy y: set y component of light location\n"
7313 "originz z: set z component of light location\n"
7314 "move x y z : adjust light location\n"
7315 "movex x: adjust x component of light location\n"
7316 "movey y: adjust y component of light location\n"
7317 "movez z: adjust z component of light location\n"
7318 "angles x y z : set light angles\n"
7319 "anglesx x: set x component of light angles\n"
7320 "anglesy y: set y component of light angles\n"
7321 "anglesz z: set z component of light angles\n"
7322 "color r g b : set color of light (can be brighter than 1 1 1)\n"
7323 "radius radius : set radius (size) of light\n"
7324 "colorscale grey : multiply color of light (1 does nothing)\n"
7325 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
7326 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
7327 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
7328 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
7329 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
7330 "cubemap basename : set filter cubemap of light\n"
7331 "shadows 1/0 : turn on/off shadows\n"
7332 "corona n : set corona intensity\n"
7333 "coronasize n : set corona size (0-1)\n"
7334 "ambient n : set ambient intensity (0-1)\n"
7335 "diffuse n : set diffuse intensity (0-1)\n"
7336 "specular n : set specular intensity (0-1)\n"
7337 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
7338 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
7339 "<nothing> : print light properties to console\n"
7343 static void R_Shadow_EditLights_CopyInfo_f(void)
7345 if (!r_editlights.integer)
7347 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
7350 if (!r_shadow_selectedlight)
7352 Con_Print("No selected light.\n");
7355 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
7356 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
7357 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
7358 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
7359 if (r_shadow_selectedlight->cubemapname)
7360 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
7362 r_shadow_bufferlight.cubemapname[0] = 0;
7363 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
7364 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
7365 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
7366 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
7367 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
7368 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
7369 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
7372 static void R_Shadow_EditLights_PasteInfo_f(void)
7374 if (!r_editlights.integer)
7376 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
7379 if (!r_shadow_selectedlight)
7381 Con_Print("No selected light.\n");
7384 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);
7387 static void R_Shadow_EditLights_Lock_f(void)
7389 if (!r_editlights.integer)
7391 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
7394 if (r_editlights_lockcursor)
7396 r_editlights_lockcursor = false;
7399 if (!r_shadow_selectedlight)
7401 Con_Print("No selected light to lock on.\n");
7404 r_editlights_lockcursor = true;
7407 static void R_Shadow_EditLights_Init(void)
7409 Cvar_RegisterVariable(&r_editlights);
7410 Cvar_RegisterVariable(&r_editlights_cursordistance);
7411 Cvar_RegisterVariable(&r_editlights_cursorpushback);
7412 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
7413 Cvar_RegisterVariable(&r_editlights_cursorgrid);
7414 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
7415 Cvar_RegisterVariable(&r_editlights_drawproperties);
7416 Cvar_RegisterVariable(&r_editlights_current_origin);
7417 Cvar_RegisterVariable(&r_editlights_current_angles);
7418 Cvar_RegisterVariable(&r_editlights_current_color);
7419 Cvar_RegisterVariable(&r_editlights_current_radius);
7420 Cvar_RegisterVariable(&r_editlights_current_corona);
7421 Cvar_RegisterVariable(&r_editlights_current_coronasize);
7422 Cvar_RegisterVariable(&r_editlights_current_style);
7423 Cvar_RegisterVariable(&r_editlights_current_shadows);
7424 Cvar_RegisterVariable(&r_editlights_current_cubemap);
7425 Cvar_RegisterVariable(&r_editlights_current_ambient);
7426 Cvar_RegisterVariable(&r_editlights_current_diffuse);
7427 Cvar_RegisterVariable(&r_editlights_current_specular);
7428 Cvar_RegisterVariable(&r_editlights_current_normalmode);
7429 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
7430 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
7431 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
7432 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)");
7433 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
7434 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
7435 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
7436 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)");
7437 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
7438 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
7439 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
7440 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
7441 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
7442 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
7443 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)");
7444 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
7450 =============================================================================
7454 =============================================================================
7457 void R_LightPoint(float *color, const vec3_t p, const int flags)
7459 int i, numlights, flag;
7460 float f, relativepoint[3], dist, dist2, lightradius2;
7465 if (r_fullbright.integer)
7467 VectorSet(color, 1, 1, 1);
7473 if (flags & LP_LIGHTMAP)
7475 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7477 VectorClear(diffuse);
7478 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, color, diffuse, n);
7479 VectorAdd(color, diffuse, color);
7482 VectorSet(color, 1, 1, 1);
7483 color[0] += r_refdef.scene.ambient;
7484 color[1] += r_refdef.scene.ambient;
7485 color[2] += r_refdef.scene.ambient;
7488 if (flags & LP_RTWORLD)
7490 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7491 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7492 for (i = 0; i < numlights; i++)
7494 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7497 light = &dlight->rtlight;
7498 if (!(light->flags & flag))
7501 lightradius2 = light->radius * light->radius;
7502 VectorSubtract(light->shadoworigin, p, relativepoint);
7503 dist2 = VectorLength2(relativepoint);
7504 if (dist2 >= lightradius2)
7506 dist = sqrt(dist2) / light->radius;
7507 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7510 // todo: add to both ambient and diffuse
7511 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)
7512 VectorMA(color, f, light->currentcolor, color);
7515 if (flags & LP_DYNLIGHT)
7518 for (i = 0;i < r_refdef.scene.numlights;i++)
7520 light = r_refdef.scene.lights[i];
7522 lightradius2 = light->radius * light->radius;
7523 VectorSubtract(light->shadoworigin, p, relativepoint);
7524 dist2 = VectorLength2(relativepoint);
7525 if (dist2 >= lightradius2)
7527 dist = sqrt(dist2) / light->radius;
7528 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7531 // todo: add to both ambient and diffuse
7532 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)
7533 VectorMA(color, f, light->color, color);
7538 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
7540 int i, numlights, flag;
7543 float relativepoint[3];
7552 if (r_fullbright.integer)
7554 VectorSet(ambient, 1, 1, 1);
7555 VectorClear(diffuse);
7556 VectorClear(lightdir);
7560 if (flags == LP_LIGHTMAP)
7562 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7563 VectorClear(diffuse);
7564 VectorClear(lightdir);
7565 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7566 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
7568 VectorSet(ambient, 1, 1, 1);
7572 memset(sample, 0, sizeof(sample));
7573 VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7575 if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7578 VectorClear(tempambient);
7580 VectorClear(relativepoint);
7581 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
7582 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
7583 VectorScale(color, r_refdef.lightmapintensity, color);
7584 VectorAdd(sample, tempambient, sample);
7585 VectorMA(sample , 0.5f , color, sample );
7586 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7587 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7588 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7589 // calculate a weighted average light direction as well
7590 intensity = VectorLength(color);
7591 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7594 if (flags & LP_RTWORLD)
7596 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7597 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7598 for (i = 0; i < numlights; i++)
7600 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7603 light = &dlight->rtlight;
7604 if (!(light->flags & flag))
7607 lightradius2 = light->radius * light->radius;
7608 VectorSubtract(light->shadoworigin, p, relativepoint);
7609 dist2 = VectorLength2(relativepoint);
7610 if (dist2 >= lightradius2)
7612 dist = sqrt(dist2) / light->radius;
7613 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
7614 if (intensity <= 0.0f)
7616 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)
7618 // scale down intensity to add to both ambient and diffuse
7619 //intensity *= 0.5f;
7620 VectorNormalize(relativepoint);
7621 VectorScale(light->currentcolor, intensity, color);
7622 VectorMA(sample , 0.5f , color, sample );
7623 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7624 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7625 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7626 // calculate a weighted average light direction as well
7627 intensity *= VectorLength(color);
7628 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7630 // FIXME: sample bouncegrid too!
7633 if (flags & LP_DYNLIGHT)
7636 for (i = 0;i < r_refdef.scene.numlights;i++)
7638 light = r_refdef.scene.lights[i];
7640 lightradius2 = light->radius * light->radius;
7641 VectorSubtract(light->shadoworigin, p, relativepoint);
7642 dist2 = VectorLength2(relativepoint);
7643 if (dist2 >= lightradius2)
7645 dist = sqrt(dist2) / light->radius;
7646 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
7647 if (intensity <= 0.0f)
7649 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)
7651 // scale down intensity to add to both ambient and diffuse
7652 //intensity *= 0.5f;
7653 VectorNormalize(relativepoint);
7654 VectorScale(light->currentcolor, intensity, color);
7655 VectorMA(sample , 0.5f , color, sample );
7656 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7657 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7658 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7659 // calculate a weighted average light direction as well
7660 intensity *= VectorLength(color);
7661 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7665 // calculate the direction we'll use to reduce the sample to a directional light source
7666 VectorCopy(sample + 12, dir);
7667 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
7668 VectorNormalize(dir);
7669 // extract the diffuse color along the chosen direction and scale it
7670 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
7671 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
7672 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
7673 // subtract some of diffuse from ambient
7674 VectorMA(sample, -0.333f, diffuse, ambient);
7675 // store the normalized lightdir
7676 VectorCopy(dir, lightdir);