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_normalizevectors = { CVAR_SAVE, "r_shadow_bouncegrid_normalizevectors", "1", "normalize random vectors (otherwise their length can vary, which dims the lighting further from the light)" };
363 cvar_t r_shadow_bouncegrid_static = {CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
364 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" };
365 cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
366 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"};
367 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"};
368 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"};
369 cvar_t r_shadow_bouncegrid_static_maxphotons = {CVAR_SAVE, "r_shadow_bouncegrid_static_maxphotons", "250000", "upper bound on photons in static mode"};
370 cvar_t r_shadow_bouncegrid_static_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_static_spacing", "64", "unit size of bouncegrid pixel when in static mode"};
371 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
372 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"};
373 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!"};
374 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
375 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
376 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
377 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
378 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
379 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
380 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
381 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
382 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
383 cvar_t r_editlights_drawproperties = {0, "r_editlights_drawproperties", "1", "draw properties of currently selected light"};
384 cvar_t r_editlights_current_origin = {0, "r_editlights_current_origin", "0 0 0", "origin of selected light"};
385 cvar_t r_editlights_current_angles = {0, "r_editlights_current_angles", "0 0 0", "angles of selected light"};
386 cvar_t r_editlights_current_color = {0, "r_editlights_current_color", "1 1 1", "color of selected light"};
387 cvar_t r_editlights_current_radius = {0, "r_editlights_current_radius", "0", "radius of selected light"};
388 cvar_t r_editlights_current_corona = {0, "r_editlights_current_corona", "0", "corona intensity of selected light"};
389 cvar_t r_editlights_current_coronasize = {0, "r_editlights_current_coronasize", "0", "corona size of selected light"};
390 cvar_t r_editlights_current_style = {0, "r_editlights_current_style", "0", "style of selected light"};
391 cvar_t r_editlights_current_shadows = {0, "r_editlights_current_shadows", "0", "shadows flag of selected light"};
392 cvar_t r_editlights_current_cubemap = {0, "r_editlights_current_cubemap", "0", "cubemap of selected light"};
393 cvar_t r_editlights_current_ambient = {0, "r_editlights_current_ambient", "0", "ambient intensity of selected light"};
394 cvar_t r_editlights_current_diffuse = {0, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"};
395 cvar_t r_editlights_current_specular = {0, "r_editlights_current_specular", "1", "specular intensity of selected light"};
396 cvar_t r_editlights_current_normalmode = {0, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"};
397 cvar_t r_editlights_current_realtimemode = {0, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"};
399 r_shadow_bouncegrid_state_t r_shadow_bouncegrid_state;
401 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
402 #define ATTENTABLESIZE 256
403 // 1D gradient, 2D circle and 3D sphere attenuation textures
404 #define ATTEN1DSIZE 32
405 #define ATTEN2DSIZE 64
406 #define ATTEN3DSIZE 32
408 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
409 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
410 static float r_shadow_attentable[ATTENTABLESIZE+1];
412 rtlight_t *r_shadow_compilingrtlight;
413 static memexpandablearray_t r_shadow_worldlightsarray;
414 dlight_t *r_shadow_selectedlight;
415 dlight_t r_shadow_bufferlight;
416 vec3_t r_editlights_cursorlocation;
417 qboolean r_editlights_lockcursor;
419 extern int con_vislines;
421 void R_Shadow_UncompileWorldLights(void);
422 void R_Shadow_ClearWorldLights(void);
423 void R_Shadow_SaveWorldLights(void);
424 void R_Shadow_LoadWorldLights(void);
425 void R_Shadow_LoadLightsFile(void);
426 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
427 void R_Shadow_EditLights_Reload_f(void);
428 void R_Shadow_ValidateCvars(void);
429 static void R_Shadow_MakeTextures(void);
431 #define EDLIGHTSPRSIZE 8
432 skinframe_t *r_editlights_sprcursor;
433 skinframe_t *r_editlights_sprlight;
434 skinframe_t *r_editlights_sprnoshadowlight;
435 skinframe_t *r_editlights_sprcubemaplight;
436 skinframe_t *r_editlights_sprcubemapnoshadowlight;
437 skinframe_t *r_editlights_sprselection;
439 static void R_Shadow_DrawModelShadowMaps(void);
440 static void R_Shadow_MakeShadowMap(int texturesize);
441 static void R_Shadow_MakeVSDCT(void);
442 static void R_Shadow_SetShadowMode(void)
444 r_shadow_shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
445 r_shadow_shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
446 r_shadow_shadowmapmaxsize = bound(r_shadow_shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, r_shadow_shadowmaptexturesize / 8);
447 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
448 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
449 r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
450 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
451 r_shadow_shadowmapsampler = false;
452 r_shadow_shadowmappcf = 0;
453 r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
454 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
455 Mod_AllocLightmap_Init(&r_shadow_shadowmapatlas_state, r_main_mempool, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize);
456 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
458 switch(vid.renderpath)
460 case RENDERPATH_GL20:
461 if(r_shadow_shadowmapfilterquality < 0)
463 if (!r_fb.usedepthtextures)
464 r_shadow_shadowmappcf = 1;
465 else if((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && vid.support.arb_shadow && r_shadow_shadowmapshadowsampler)
467 r_shadow_shadowmapsampler = true;
468 r_shadow_shadowmappcf = 1;
470 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
471 r_shadow_shadowmappcf = 1;
472 else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa"))
473 r_shadow_shadowmappcf = 1;
475 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
479 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
480 switch (r_shadow_shadowmapfilterquality)
485 r_shadow_shadowmappcf = 1;
488 r_shadow_shadowmappcf = 1;
491 r_shadow_shadowmappcf = 2;
495 if (!r_fb.usedepthtextures)
496 r_shadow_shadowmapsampler = false;
497 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
499 case RENDERPATH_D3D9:
500 case RENDERPATH_D3D10:
501 case RENDERPATH_D3D11:
502 case RENDERPATH_SOFT:
503 r_shadow_shadowmapsampler = false;
504 r_shadow_shadowmappcf = 1;
505 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
507 case RENDERPATH_GL11:
508 case RENDERPATH_GL13:
509 case RENDERPATH_GLES1:
510 case RENDERPATH_GLES2:
515 if(R_CompileShader_CheckStaticParms())
519 qboolean R_Shadow_ShadowMappingEnabled(void)
521 switch (r_shadow_shadowmode)
523 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
530 static void R_Shadow_FreeShadowMaps(void)
532 Mod_AllocLightmap_Free(&r_shadow_shadowmapatlas_state);
534 R_Shadow_SetShadowMode();
536 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
540 if (r_shadow_shadowmap2ddepthtexture)
541 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
542 r_shadow_shadowmap2ddepthtexture = NULL;
544 if (r_shadow_shadowmap2ddepthbuffer)
545 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
546 r_shadow_shadowmap2ddepthbuffer = NULL;
548 if (r_shadow_shadowmapvsdcttexture)
549 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
550 r_shadow_shadowmapvsdcttexture = NULL;
553 static void r_shadow_start(void)
555 // allocate vertex processing arrays
556 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
557 r_shadow_attenuationgradienttexture = NULL;
558 r_shadow_attenuation2dtexture = NULL;
559 r_shadow_attenuation3dtexture = NULL;
560 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
561 r_shadow_shadowmap2ddepthtexture = NULL;
562 r_shadow_shadowmap2ddepthbuffer = NULL;
563 r_shadow_shadowmapvsdcttexture = NULL;
564 r_shadow_shadowmapmaxsize = 0;
565 r_shadow_shadowmaptexturesize = 0;
566 r_shadow_shadowmapfilterquality = -1;
567 r_shadow_shadowmapdepthbits = 0;
568 r_shadow_shadowmapvsdct = false;
569 r_shadow_shadowmapsampler = false;
570 r_shadow_shadowmappcf = 0;
573 R_Shadow_FreeShadowMaps();
575 r_shadow_texturepool = NULL;
576 r_shadow_filters_texturepool = NULL;
577 R_Shadow_ValidateCvars();
578 R_Shadow_MakeTextures();
579 r_shadow_scenemaxlights = 0;
580 r_shadow_scenenumlights = 0;
581 r_shadow_scenelightlist = NULL;
582 maxshadowtriangles = 0;
583 shadowelements = NULL;
584 maxshadowvertices = 0;
585 shadowvertex3f = NULL;
593 shadowmarklist = NULL;
598 shadowsideslist = NULL;
599 r_shadow_buffer_numleafpvsbytes = 0;
600 r_shadow_buffer_visitingleafpvs = NULL;
601 r_shadow_buffer_leafpvs = NULL;
602 r_shadow_buffer_leaflist = NULL;
603 r_shadow_buffer_numsurfacepvsbytes = 0;
604 r_shadow_buffer_surfacepvs = NULL;
605 r_shadow_buffer_surfacelist = NULL;
606 r_shadow_buffer_surfacesides = NULL;
607 r_shadow_buffer_numshadowtrispvsbytes = 0;
608 r_shadow_buffer_shadowtrispvs = NULL;
609 r_shadow_buffer_numlighttrispvsbytes = 0;
610 r_shadow_buffer_lighttrispvs = NULL;
612 r_shadow_usingdeferredprepass = false;
613 r_shadow_prepass_width = r_shadow_prepass_height = 0;
615 // determine renderpath specific capabilities, we don't need to figure
616 // these out per frame...
617 switch(vid.renderpath)
619 case RENDERPATH_GL20:
620 r_shadow_bouncegrid_state.allowdirectionalshading = true;
621 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
623 case RENDERPATH_GLES2:
624 // for performance reasons, do not use directional shading on GLES devices
625 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
627 // these renderpaths do not currently have the code to display the bouncegrid, so disable it on them...
628 case RENDERPATH_GL11:
629 case RENDERPATH_GL13:
630 case RENDERPATH_GLES1:
631 case RENDERPATH_SOFT:
632 case RENDERPATH_D3D9:
633 case RENDERPATH_D3D10:
634 case RENDERPATH_D3D11:
639 static void R_Shadow_FreeDeferred(void);
640 static void r_shadow_shutdown(void)
643 R_Shadow_UncompileWorldLights();
645 R_Shadow_FreeShadowMaps();
647 r_shadow_usingdeferredprepass = false;
648 if (r_shadow_prepass_width)
649 R_Shadow_FreeDeferred();
650 r_shadow_prepass_width = r_shadow_prepass_height = 0;
653 r_shadow_scenemaxlights = 0;
654 r_shadow_scenenumlights = 0;
655 if (r_shadow_scenelightlist)
656 Mem_Free(r_shadow_scenelightlist);
657 r_shadow_scenelightlist = NULL;
658 r_shadow_bouncegrid_state.highpixels = NULL;
659 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
660 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
661 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
662 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
663 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
664 r_shadow_bouncegrid_state.maxsplatpaths = 0;
665 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
666 r_shadow_attenuationgradienttexture = NULL;
667 r_shadow_attenuation2dtexture = NULL;
668 r_shadow_attenuation3dtexture = NULL;
669 R_FreeTexturePool(&r_shadow_texturepool);
670 R_FreeTexturePool(&r_shadow_filters_texturepool);
671 maxshadowtriangles = 0;
673 Mem_Free(shadowelements);
674 shadowelements = NULL;
676 Mem_Free(shadowvertex3f);
677 shadowvertex3f = NULL;
680 Mem_Free(vertexupdate);
683 Mem_Free(vertexremap);
689 Mem_Free(shadowmark);
692 Mem_Free(shadowmarklist);
693 shadowmarklist = NULL;
698 Mem_Free(shadowsides);
701 Mem_Free(shadowsideslist);
702 shadowsideslist = NULL;
703 r_shadow_buffer_numleafpvsbytes = 0;
704 if (r_shadow_buffer_visitingleafpvs)
705 Mem_Free(r_shadow_buffer_visitingleafpvs);
706 r_shadow_buffer_visitingleafpvs = NULL;
707 if (r_shadow_buffer_leafpvs)
708 Mem_Free(r_shadow_buffer_leafpvs);
709 r_shadow_buffer_leafpvs = NULL;
710 if (r_shadow_buffer_leaflist)
711 Mem_Free(r_shadow_buffer_leaflist);
712 r_shadow_buffer_leaflist = NULL;
713 r_shadow_buffer_numsurfacepvsbytes = 0;
714 if (r_shadow_buffer_surfacepvs)
715 Mem_Free(r_shadow_buffer_surfacepvs);
716 r_shadow_buffer_surfacepvs = NULL;
717 if (r_shadow_buffer_surfacelist)
718 Mem_Free(r_shadow_buffer_surfacelist);
719 r_shadow_buffer_surfacelist = NULL;
720 if (r_shadow_buffer_surfacesides)
721 Mem_Free(r_shadow_buffer_surfacesides);
722 r_shadow_buffer_surfacesides = NULL;
723 r_shadow_buffer_numshadowtrispvsbytes = 0;
724 if (r_shadow_buffer_shadowtrispvs)
725 Mem_Free(r_shadow_buffer_shadowtrispvs);
726 r_shadow_buffer_numlighttrispvsbytes = 0;
727 if (r_shadow_buffer_lighttrispvs)
728 Mem_Free(r_shadow_buffer_lighttrispvs);
731 static void r_shadow_newmap(void)
733 r_shadow_bouncegrid_state.highpixels = NULL;
734 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
735 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
736 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
737 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
738 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
739 r_shadow_bouncegrid_state.maxsplatpaths = 0;
740 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
741 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
742 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
743 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
744 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
745 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
746 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
747 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
748 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
749 R_Shadow_EditLights_Reload_f();
752 void R_Shadow_Init(void)
754 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
755 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
756 Cvar_RegisterVariable(&r_shadow_usebihculling);
757 Cvar_RegisterVariable(&r_shadow_usenormalmap);
758 Cvar_RegisterVariable(&r_shadow_debuglight);
759 Cvar_RegisterVariable(&r_shadow_deferred);
760 Cvar_RegisterVariable(&r_shadow_gloss);
761 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
762 Cvar_RegisterVariable(&r_shadow_glossintensity);
763 Cvar_RegisterVariable(&r_shadow_glossexponent);
764 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
765 Cvar_RegisterVariable(&r_shadow_glossexact);
766 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
767 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
768 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
769 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
770 Cvar_RegisterVariable(&r_shadow_projectdistance);
771 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
772 Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
773 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
774 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
775 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
776 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
777 Cvar_RegisterVariable(&r_shadow_realtime_world);
778 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
779 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
780 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
781 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
782 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
783 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
784 Cvar_RegisterVariable(&r_shadow_scissor);
785 Cvar_RegisterVariable(&r_shadow_shadowmapping);
786 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
787 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
788 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
789 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
790 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
791 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
792 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
793 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturesize);
794 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
795 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
796 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
797 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
798 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
799 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
800 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
801 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
802 Cvar_RegisterVariable(&r_shadow_polygonfactor);
803 Cvar_RegisterVariable(&r_shadow_polygonoffset);
804 Cvar_RegisterVariable(&r_shadow_texture3d);
805 Cvar_RegisterVariable(&r_shadow_bouncegrid);
806 Cvar_RegisterVariable(&r_shadow_bouncegrid_blur);
807 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
808 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_bounceminimumintensity);
809 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_culllightpaths);
810 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_directionalshading);
811 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_dlightparticlemultiplier);
812 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_hitmodels);
813 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_energyperphoton);
814 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_lightradiusscale);
815 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxbounce);
816 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxphotons);
817 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_spacing);
818 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_stablerandom);
819 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_updateinterval);
820 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_x);
821 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_y);
822 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_z);
823 Cvar_RegisterVariable(&r_shadow_bouncegrid_floatcolors);
824 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
825 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
826 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize);
827 Cvar_RegisterVariable(&r_shadow_bouncegrid_normalizevectors);
828 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
829 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
830 Cvar_RegisterVariable(&r_shadow_bouncegrid_sortlightpaths);
831 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
832 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_bounceminimumintensity);
833 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
834 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_energyperphoton);
835 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
836 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
837 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxphotons);
838 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_spacing);
839 Cvar_RegisterVariable(&r_coronas);
840 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
841 Cvar_RegisterVariable(&r_coronas_occlusionquery);
842 Cvar_RegisterVariable(&gl_flashblend);
843 Cvar_RegisterVariable(&gl_ext_separatestencil);
844 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
845 R_Shadow_EditLights_Init();
846 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
847 r_shadow_scenemaxlights = 0;
848 r_shadow_scenenumlights = 0;
849 r_shadow_scenelightlist = NULL;
850 maxshadowtriangles = 0;
851 shadowelements = NULL;
852 maxshadowvertices = 0;
853 shadowvertex3f = NULL;
861 shadowmarklist = NULL;
866 shadowsideslist = NULL;
867 r_shadow_buffer_numleafpvsbytes = 0;
868 r_shadow_buffer_visitingleafpvs = NULL;
869 r_shadow_buffer_leafpvs = NULL;
870 r_shadow_buffer_leaflist = NULL;
871 r_shadow_buffer_numsurfacepvsbytes = 0;
872 r_shadow_buffer_surfacepvs = NULL;
873 r_shadow_buffer_surfacelist = NULL;
874 r_shadow_buffer_surfacesides = NULL;
875 r_shadow_buffer_shadowtrispvs = NULL;
876 r_shadow_buffer_lighttrispvs = NULL;
877 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
880 matrix4x4_t matrix_attenuationxyz =
883 {0.5, 0.0, 0.0, 0.5},
884 {0.0, 0.5, 0.0, 0.5},
885 {0.0, 0.0, 0.5, 0.5},
890 matrix4x4_t matrix_attenuationz =
893 {0.0, 0.0, 0.5, 0.5},
894 {0.0, 0.0, 0.0, 0.5},
895 {0.0, 0.0, 0.0, 0.5},
900 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
902 numvertices = ((numvertices + 255) & ~255) * vertscale;
903 numtriangles = ((numtriangles + 255) & ~255) * triscale;
904 // make sure shadowelements is big enough for this volume
905 if (maxshadowtriangles < numtriangles)
907 maxshadowtriangles = numtriangles;
909 Mem_Free(shadowelements);
910 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
912 // make sure shadowvertex3f is big enough for this volume
913 if (maxshadowvertices < numvertices)
915 maxshadowvertices = numvertices;
917 Mem_Free(shadowvertex3f);
918 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
922 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
924 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
925 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
926 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
927 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
928 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
930 if (r_shadow_buffer_visitingleafpvs)
931 Mem_Free(r_shadow_buffer_visitingleafpvs);
932 if (r_shadow_buffer_leafpvs)
933 Mem_Free(r_shadow_buffer_leafpvs);
934 if (r_shadow_buffer_leaflist)
935 Mem_Free(r_shadow_buffer_leaflist);
936 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
937 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
938 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
939 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
941 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
943 if (r_shadow_buffer_surfacepvs)
944 Mem_Free(r_shadow_buffer_surfacepvs);
945 if (r_shadow_buffer_surfacelist)
946 Mem_Free(r_shadow_buffer_surfacelist);
947 if (r_shadow_buffer_surfacesides)
948 Mem_Free(r_shadow_buffer_surfacesides);
949 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
950 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
951 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
952 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
954 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
956 if (r_shadow_buffer_shadowtrispvs)
957 Mem_Free(r_shadow_buffer_shadowtrispvs);
958 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
959 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
961 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
963 if (r_shadow_buffer_lighttrispvs)
964 Mem_Free(r_shadow_buffer_lighttrispvs);
965 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
966 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
970 void R_Shadow_PrepareShadowMark(int numtris)
972 // make sure shadowmark is big enough for this volume
973 if (maxshadowmark < numtris)
975 maxshadowmark = numtris;
977 Mem_Free(shadowmark);
979 Mem_Free(shadowmarklist);
980 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
981 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
985 // if shadowmarkcount wrapped we clear the array and adjust accordingly
986 if (shadowmarkcount == 0)
989 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
994 void R_Shadow_PrepareShadowSides(int numtris)
996 if (maxshadowsides < numtris)
998 maxshadowsides = numtris;
1000 Mem_Free(shadowsides);
1001 if (shadowsideslist)
1002 Mem_Free(shadowsideslist);
1003 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
1004 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
1009 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)
1012 int outtriangles = 0, outvertices = 0;
1014 const float *vertex;
1015 float ratio, direction[3], projectvector[3];
1017 if (projectdirection)
1018 VectorScale(projectdirection, projectdistance, projectvector);
1020 VectorClear(projectvector);
1022 // create the vertices
1023 if (projectdirection)
1025 for (i = 0;i < numshadowmarktris;i++)
1027 element = inelement3i + shadowmarktris[i] * 3;
1028 for (j = 0;j < 3;j++)
1030 if (vertexupdate[element[j]] != vertexupdatenum)
1032 vertexupdate[element[j]] = vertexupdatenum;
1033 vertexremap[element[j]] = outvertices;
1034 vertex = invertex3f + element[j] * 3;
1035 // project one copy of the vertex according to projectvector
1036 VectorCopy(vertex, outvertex3f);
1037 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1046 for (i = 0;i < numshadowmarktris;i++)
1048 element = inelement3i + shadowmarktris[i] * 3;
1049 for (j = 0;j < 3;j++)
1051 if (vertexupdate[element[j]] != vertexupdatenum)
1053 vertexupdate[element[j]] = vertexupdatenum;
1054 vertexremap[element[j]] = outvertices;
1055 vertex = invertex3f + element[j] * 3;
1056 // project one copy of the vertex to the sphere radius of the light
1057 // (FIXME: would projecting it to the light box be better?)
1058 VectorSubtract(vertex, projectorigin, direction);
1059 ratio = projectdistance / VectorLength(direction);
1060 VectorCopy(vertex, outvertex3f);
1061 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1069 if (r_shadow_frontsidecasting.integer)
1071 for (i = 0;i < numshadowmarktris;i++)
1073 int remappedelement[3];
1075 const int *neighbortriangle;
1077 markindex = shadowmarktris[i] * 3;
1078 element = inelement3i + markindex;
1079 neighbortriangle = inneighbor3i + markindex;
1080 // output the front and back triangles
1081 outelement3i[0] = vertexremap[element[0]];
1082 outelement3i[1] = vertexremap[element[1]];
1083 outelement3i[2] = vertexremap[element[2]];
1084 outelement3i[3] = vertexremap[element[2]] + 1;
1085 outelement3i[4] = vertexremap[element[1]] + 1;
1086 outelement3i[5] = vertexremap[element[0]] + 1;
1090 // output the sides (facing outward from this triangle)
1091 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1093 remappedelement[0] = vertexremap[element[0]];
1094 remappedelement[1] = vertexremap[element[1]];
1095 outelement3i[0] = remappedelement[1];
1096 outelement3i[1] = remappedelement[0];
1097 outelement3i[2] = remappedelement[0] + 1;
1098 outelement3i[3] = remappedelement[1];
1099 outelement3i[4] = remappedelement[0] + 1;
1100 outelement3i[5] = remappedelement[1] + 1;
1105 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1107 remappedelement[1] = vertexremap[element[1]];
1108 remappedelement[2] = vertexremap[element[2]];
1109 outelement3i[0] = remappedelement[2];
1110 outelement3i[1] = remappedelement[1];
1111 outelement3i[2] = remappedelement[1] + 1;
1112 outelement3i[3] = remappedelement[2];
1113 outelement3i[4] = remappedelement[1] + 1;
1114 outelement3i[5] = remappedelement[2] + 1;
1119 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1121 remappedelement[0] = vertexremap[element[0]];
1122 remappedelement[2] = vertexremap[element[2]];
1123 outelement3i[0] = remappedelement[0];
1124 outelement3i[1] = remappedelement[2];
1125 outelement3i[2] = remappedelement[2] + 1;
1126 outelement3i[3] = remappedelement[0];
1127 outelement3i[4] = remappedelement[2] + 1;
1128 outelement3i[5] = remappedelement[0] + 1;
1137 for (i = 0;i < numshadowmarktris;i++)
1139 int remappedelement[3];
1141 const int *neighbortriangle;
1143 markindex = shadowmarktris[i] * 3;
1144 element = inelement3i + markindex;
1145 neighbortriangle = inneighbor3i + markindex;
1146 // output the front and back triangles
1147 outelement3i[0] = vertexremap[element[2]];
1148 outelement3i[1] = vertexremap[element[1]];
1149 outelement3i[2] = vertexremap[element[0]];
1150 outelement3i[3] = vertexremap[element[0]] + 1;
1151 outelement3i[4] = vertexremap[element[1]] + 1;
1152 outelement3i[5] = vertexremap[element[2]] + 1;
1156 // output the sides (facing outward from this triangle)
1157 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1159 remappedelement[0] = vertexremap[element[0]];
1160 remappedelement[1] = vertexremap[element[1]];
1161 outelement3i[0] = remappedelement[0];
1162 outelement3i[1] = remappedelement[1];
1163 outelement3i[2] = remappedelement[1] + 1;
1164 outelement3i[3] = remappedelement[0];
1165 outelement3i[4] = remappedelement[1] + 1;
1166 outelement3i[5] = remappedelement[0] + 1;
1171 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1173 remappedelement[1] = vertexremap[element[1]];
1174 remappedelement[2] = vertexremap[element[2]];
1175 outelement3i[0] = remappedelement[1];
1176 outelement3i[1] = remappedelement[2];
1177 outelement3i[2] = remappedelement[2] + 1;
1178 outelement3i[3] = remappedelement[1];
1179 outelement3i[4] = remappedelement[2] + 1;
1180 outelement3i[5] = remappedelement[1] + 1;
1185 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1187 remappedelement[0] = vertexremap[element[0]];
1188 remappedelement[2] = vertexremap[element[2]];
1189 outelement3i[0] = remappedelement[2];
1190 outelement3i[1] = remappedelement[0];
1191 outelement3i[2] = remappedelement[0] + 1;
1192 outelement3i[3] = remappedelement[2];
1193 outelement3i[4] = remappedelement[0] + 1;
1194 outelement3i[5] = remappedelement[2] + 1;
1202 *outnumvertices = outvertices;
1203 return outtriangles;
1206 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)
1209 int outtriangles = 0, outvertices = 0;
1211 const float *vertex;
1212 float ratio, direction[3], projectvector[3];
1215 if (projectdirection)
1216 VectorScale(projectdirection, projectdistance, projectvector);
1218 VectorClear(projectvector);
1220 for (i = 0;i < numshadowmarktris;i++)
1222 int remappedelement[3];
1224 const int *neighbortriangle;
1226 markindex = shadowmarktris[i] * 3;
1227 neighbortriangle = inneighbor3i + markindex;
1228 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1229 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1230 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1231 if (side[0] + side[1] + side[2] == 0)
1235 element = inelement3i + markindex;
1237 // create the vertices
1238 for (j = 0;j < 3;j++)
1240 if (side[j] + side[j+1] == 0)
1243 if (vertexupdate[k] != vertexupdatenum)
1245 vertexupdate[k] = vertexupdatenum;
1246 vertexremap[k] = outvertices;
1247 vertex = invertex3f + k * 3;
1248 VectorCopy(vertex, outvertex3f);
1249 if (projectdirection)
1251 // project one copy of the vertex according to projectvector
1252 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1256 // project one copy of the vertex to the sphere radius of the light
1257 // (FIXME: would projecting it to the light box be better?)
1258 VectorSubtract(vertex, projectorigin, direction);
1259 ratio = projectdistance / VectorLength(direction);
1260 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1267 // output the sides (facing outward from this triangle)
1270 remappedelement[0] = vertexremap[element[0]];
1271 remappedelement[1] = vertexremap[element[1]];
1272 outelement3i[0] = remappedelement[1];
1273 outelement3i[1] = remappedelement[0];
1274 outelement3i[2] = remappedelement[0] + 1;
1275 outelement3i[3] = remappedelement[1];
1276 outelement3i[4] = remappedelement[0] + 1;
1277 outelement3i[5] = remappedelement[1] + 1;
1284 remappedelement[1] = vertexremap[element[1]];
1285 remappedelement[2] = vertexremap[element[2]];
1286 outelement3i[0] = remappedelement[2];
1287 outelement3i[1] = remappedelement[1];
1288 outelement3i[2] = remappedelement[1] + 1;
1289 outelement3i[3] = remappedelement[2];
1290 outelement3i[4] = remappedelement[1] + 1;
1291 outelement3i[5] = remappedelement[2] + 1;
1298 remappedelement[0] = vertexremap[element[0]];
1299 remappedelement[2] = vertexremap[element[2]];
1300 outelement3i[0] = remappedelement[0];
1301 outelement3i[1] = remappedelement[2];
1302 outelement3i[2] = remappedelement[2] + 1;
1303 outelement3i[3] = remappedelement[0];
1304 outelement3i[4] = remappedelement[2] + 1;
1305 outelement3i[5] = remappedelement[0] + 1;
1312 *outnumvertices = outvertices;
1313 return outtriangles;
1316 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)
1322 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1324 tend = firsttriangle + numtris;
1325 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1327 // surface box entirely inside light box, no box cull
1328 if (projectdirection)
1330 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1332 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1333 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1334 shadowmarklist[numshadowmark++] = t;
1339 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1340 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1341 shadowmarklist[numshadowmark++] = t;
1346 // surface box not entirely inside light box, cull each triangle
1347 if (projectdirection)
1349 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1351 v[0] = invertex3f + e[0] * 3;
1352 v[1] = invertex3f + e[1] * 3;
1353 v[2] = invertex3f + e[2] * 3;
1354 TriangleNormal(v[0], v[1], v[2], normal);
1355 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1356 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1357 shadowmarklist[numshadowmark++] = t;
1362 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1364 v[0] = invertex3f + e[0] * 3;
1365 v[1] = invertex3f + e[1] * 3;
1366 v[2] = invertex3f + e[2] * 3;
1367 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1368 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1369 shadowmarklist[numshadowmark++] = t;
1375 static qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1380 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1382 // check if the shadow volume intersects the near plane
1384 // a ray between the eye and light origin may intersect the caster,
1385 // indicating that the shadow may touch the eye location, however we must
1386 // test the near plane (a polygon), not merely the eye location, so it is
1387 // easiest to enlarge the caster bounding shape slightly for this.
1393 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)
1395 int i, tris, outverts;
1396 if (projectdistance < 0.1)
1398 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1401 if (!numverts || !nummarktris)
1403 // make sure shadowelements is big enough for this volume
1404 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1405 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1407 if (maxvertexupdate < numverts)
1409 maxvertexupdate = numverts;
1411 Mem_Free(vertexupdate);
1413 Mem_Free(vertexremap);
1414 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1415 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1416 vertexupdatenum = 0;
1419 if (vertexupdatenum == 0)
1421 vertexupdatenum = 1;
1422 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1423 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1426 for (i = 0;i < nummarktris;i++)
1427 shadowmark[marktris[i]] = shadowmarkcount;
1429 if (r_shadow_compilingrtlight)
1431 // if we're compiling an rtlight, capture the mesh
1432 //tris = R_Shadow_ConstructShadowVolume_ZPass(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_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1434 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1435 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1437 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1439 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1440 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1441 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1445 // decide which type of shadow to generate and set stencil mode
1446 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1447 // generate the sides or a solid volume, depending on type
1448 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1449 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1451 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1452 r_refdef.stats[r_stat_lights_dynamicshadowtriangles] += tris;
1453 r_refdef.stats[r_stat_lights_shadowtriangles] += tris;
1454 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1456 // increment stencil if frontface is infront of depthbuffer
1457 GL_CullFace(r_refdef.view.cullface_front);
1458 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1459 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1460 // decrement stencil if backface is infront of depthbuffer
1461 GL_CullFace(r_refdef.view.cullface_back);
1462 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1464 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1466 // decrement stencil if backface is behind depthbuffer
1467 GL_CullFace(r_refdef.view.cullface_front);
1468 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1469 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1470 // increment stencil if frontface is behind depthbuffer
1471 GL_CullFace(r_refdef.view.cullface_back);
1472 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1474 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1475 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1479 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1481 // p1, p2, p3 are in the cubemap's local coordinate system
1482 // bias = border/(size - border)
1485 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1486 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1487 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1488 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1490 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1491 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1492 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1493 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1495 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1496 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1497 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1499 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1500 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1501 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1502 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1504 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1505 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1506 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1507 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1509 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1510 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1511 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1513 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1514 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1515 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1516 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1518 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1519 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1520 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1521 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1523 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1524 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1525 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1530 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1532 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1533 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1536 VectorSubtract(maxs, mins, radius);
1537 VectorScale(radius, 0.5f, radius);
1538 VectorAdd(mins, radius, center);
1539 Matrix4x4_Transform(worldtolight, center, lightcenter);
1540 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1541 VectorSubtract(lightcenter, lightradius, pmin);
1542 VectorAdd(lightcenter, lightradius, pmax);
1544 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1545 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1546 if(ap1 > bias*an1 && ap2 > bias*an2)
1548 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1549 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1550 if(an1 > bias*ap1 && an2 > bias*ap2)
1552 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1553 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1555 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1556 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1557 if(ap1 > bias*an1 && ap2 > bias*an2)
1559 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1560 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1561 if(an1 > bias*ap1 && an2 > bias*ap2)
1563 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1564 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1566 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1567 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1568 if(ap1 > bias*an1 && ap2 > bias*an2)
1570 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1571 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1572 if(an1 > bias*ap1 && an2 > bias*ap2)
1574 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1575 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1580 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1582 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1584 // p is in the cubemap's local coordinate system
1585 // bias = border/(size - border)
1586 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1587 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1588 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1590 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1591 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1592 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1593 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1594 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1595 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1599 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1603 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1604 float scale = (size - 2*border)/size, len;
1605 float bias = border / (float)(size - border), dp, dn, ap, an;
1606 // check if cone enclosing side would cross frustum plane
1607 scale = 2 / (scale*scale + 2);
1608 Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
1609 for (i = 0;i < 5;i++)
1611 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
1613 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1614 len = scale*VectorLength2(n);
1615 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1616 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1617 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1619 if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1621 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1622 len = scale*VectorLength2(n);
1623 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1624 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1625 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1627 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1628 // check if frustum corners/origin cross plane sides
1630 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1631 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1632 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1633 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1634 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1635 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1636 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1637 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1638 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1639 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1640 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1641 for (i = 0;i < 4;i++)
1643 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1644 VectorSubtract(n, p, n);
1645 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1646 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1647 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1648 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1649 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1650 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1651 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1652 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1653 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1656 // finite version, assumes corners are a finite distance from origin dependent on far plane
1657 for (i = 0;i < 5;i++)
1659 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1660 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1661 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1662 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1663 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1664 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1665 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1666 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1667 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1668 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1671 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1674 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)
1682 int mask, surfacemask = 0;
1683 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1685 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1686 tend = firsttriangle + numtris;
1687 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1689 // surface box entirely inside light box, no box cull
1690 if (projectdirection)
1692 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1694 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1695 TriangleNormal(v[0], v[1], v[2], normal);
1696 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1698 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1699 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1700 surfacemask |= mask;
1703 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;
1704 shadowsides[numshadowsides] = mask;
1705 shadowsideslist[numshadowsides++] = t;
1712 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1714 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1715 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1717 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1718 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1719 surfacemask |= mask;
1722 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;
1723 shadowsides[numshadowsides] = mask;
1724 shadowsideslist[numshadowsides++] = t;
1732 // surface box not entirely inside light box, cull each triangle
1733 if (projectdirection)
1735 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1737 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1738 TriangleNormal(v[0], v[1], v[2], normal);
1739 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1740 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1742 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1743 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1744 surfacemask |= mask;
1747 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;
1748 shadowsides[numshadowsides] = mask;
1749 shadowsideslist[numshadowsides++] = t;
1756 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1758 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1759 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1760 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1762 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1763 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1764 surfacemask |= mask;
1767 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;
1768 shadowsides[numshadowsides] = mask;
1769 shadowsideslist[numshadowsides++] = t;
1778 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)
1780 int i, j, outtriangles = 0;
1781 int *outelement3i[6];
1782 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1784 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1785 // make sure shadowelements is big enough for this mesh
1786 if (maxshadowtriangles < outtriangles)
1787 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1789 // compute the offset and size of the separate index lists for each cubemap side
1791 for (i = 0;i < 6;i++)
1793 outelement3i[i] = shadowelements + outtriangles * 3;
1794 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1795 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1796 outtriangles += sidetotals[i];
1799 // gather up the (sparse) triangles into separate index lists for each cubemap side
1800 for (i = 0;i < numsidetris;i++)
1802 const int *element = elements + sidetris[i] * 3;
1803 for (j = 0;j < 6;j++)
1805 if (sides[i] & (1 << j))
1807 outelement3i[j][0] = element[0];
1808 outelement3i[j][1] = element[1];
1809 outelement3i[j][2] = element[2];
1810 outelement3i[j] += 3;
1815 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1818 static void R_Shadow_MakeTextures_MakeCorona(void)
1822 unsigned char pixels[32][32][4];
1823 for (y = 0;y < 32;y++)
1825 dy = (y - 15.5f) * (1.0f / 16.0f);
1826 for (x = 0;x < 32;x++)
1828 dx = (x - 15.5f) * (1.0f / 16.0f);
1829 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1830 a = bound(0, a, 255);
1831 pixels[y][x][0] = a;
1832 pixels[y][x][1] = a;
1833 pixels[y][x][2] = a;
1834 pixels[y][x][3] = 255;
1837 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, false);
1840 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1842 float dist = sqrt(x*x+y*y+z*z);
1843 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1844 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1845 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1848 static void R_Shadow_MakeTextures(void)
1851 float intensity, dist;
1853 R_Shadow_FreeShadowMaps();
1854 R_FreeTexturePool(&r_shadow_texturepool);
1855 r_shadow_texturepool = R_AllocTexturePool();
1856 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1857 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1858 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1859 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1860 for (x = 0;x <= ATTENTABLESIZE;x++)
1862 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1863 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1864 r_shadow_attentable[x] = bound(0, intensity, 1);
1866 // 1D gradient texture
1867 for (x = 0;x < ATTEN1DSIZE;x++)
1868 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1869 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1870 // 2D circle texture
1871 for (y = 0;y < ATTEN2DSIZE;y++)
1872 for (x = 0;x < ATTEN2DSIZE;x++)
1873 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);
1874 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1875 // 3D sphere texture
1876 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1878 for (z = 0;z < ATTEN3DSIZE;z++)
1879 for (y = 0;y < ATTEN3DSIZE;y++)
1880 for (x = 0;x < ATTEN3DSIZE;x++)
1881 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));
1882 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);
1885 r_shadow_attenuation3dtexture = NULL;
1888 R_Shadow_MakeTextures_MakeCorona();
1890 // Editor light sprites
1891 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1908 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1909 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1926 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1927 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1944 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1945 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1962 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1963 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1980 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1981 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1998 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
2001 void R_Shadow_ValidateCvars(void)
2003 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
2004 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
2005 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
2006 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
2007 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
2008 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
2011 void R_Shadow_RenderMode_Begin(void)
2017 R_Shadow_ValidateCvars();
2019 if (!r_shadow_attenuation2dtexture
2020 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
2021 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
2022 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
2023 R_Shadow_MakeTextures();
2026 R_Mesh_ResetTextureState();
2027 GL_BlendFunc(GL_ONE, GL_ZERO);
2028 GL_DepthRange(0, 1);
2029 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
2031 GL_DepthMask(false);
2032 GL_Color(0, 0, 0, 1);
2033 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2035 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2037 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
2039 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
2040 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
2042 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
2044 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
2045 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
2049 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
2050 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
2053 switch(vid.renderpath)
2055 case RENDERPATH_GL20:
2056 case RENDERPATH_D3D9:
2057 case RENDERPATH_D3D10:
2058 case RENDERPATH_D3D11:
2059 case RENDERPATH_SOFT:
2060 case RENDERPATH_GLES2:
2061 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
2063 case RENDERPATH_GL11:
2064 case RENDERPATH_GL13:
2065 case RENDERPATH_GLES1:
2066 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
2067 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
2068 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
2069 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
2070 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
2071 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
2073 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
2079 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
2080 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
2081 r_shadow_drawbuffer = drawbuffer;
2082 r_shadow_readbuffer = readbuffer;
2084 r_shadow_cullface_front = r_refdef.view.cullface_front;
2085 r_shadow_cullface_back = r_refdef.view.cullface_back;
2088 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
2090 rsurface.rtlight = rtlight;
2093 void R_Shadow_RenderMode_Reset(void)
2095 R_Mesh_ResetTextureState();
2096 R_Mesh_SetRenderTargets(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture, NULL, NULL, NULL);
2097 R_SetViewport(&r_refdef.view.viewport);
2098 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
2099 GL_DepthRange(0, 1);
2101 GL_DepthMask(false);
2102 GL_DepthFunc(GL_LEQUAL);
2103 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2104 r_refdef.view.cullface_front = r_shadow_cullface_front;
2105 r_refdef.view.cullface_back = r_shadow_cullface_back;
2106 GL_CullFace(r_refdef.view.cullface_back);
2107 GL_Color(1, 1, 1, 1);
2108 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2109 GL_BlendFunc(GL_ONE, GL_ZERO);
2110 R_SetupShader_Generic_NoTexture(false, false);
2111 r_shadow_usingshadowmap2d = false;
2112 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2115 void R_Shadow_ClearStencil(void)
2117 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2118 r_refdef.stats[r_stat_lights_clears]++;
2121 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2123 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2124 if (r_shadow_rendermode == mode)
2126 R_Shadow_RenderMode_Reset();
2127 GL_DepthFunc(GL_LESS);
2128 GL_ColorMask(0, 0, 0, 0);
2129 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2130 GL_CullFace(GL_NONE);
2131 R_SetupShader_DepthOrShadow(false, false, false); // FIXME test if we have a skeletal model?
2132 r_shadow_rendermode = mode;
2137 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2138 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2139 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2141 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2142 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2143 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2148 static void R_Shadow_MakeVSDCT(void)
2150 // maps to a 2x3 texture rectangle with normalized coordinates
2155 // stores abs(dir.xy), offset.xy/2.5
2156 unsigned char data[4*6] =
2158 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2159 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2160 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2161 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2162 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2163 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2165 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2168 static void R_Shadow_MakeShadowMap(int texturesize)
2170 switch (r_shadow_shadowmode)
2172 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2173 if (r_shadow_shadowmap2ddepthtexture) return;
2174 if (r_fb.usedepthtextures)
2176 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);
2177 r_shadow_shadowmap2ddepthbuffer = NULL;
2178 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2182 r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", texturesize, texturesize, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2183 r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
2184 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2192 void R_Shadow_ClearShadowMapTexture(void)
2194 r_viewport_t viewport;
2195 float clearcolor[4];
2197 // if they don't exist, create our textures now
2198 if (!r_shadow_shadowmap2ddepthtexture)
2199 R_Shadow_MakeShadowMap(r_shadow_shadowmaptexturesize);
2200 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2201 R_Shadow_MakeVSDCT();
2203 // we're setting up to render shadowmaps, so change rendermode
2204 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2206 R_Mesh_ResetTextureState();
2207 R_Shadow_RenderMode_Reset();
2208 if (r_shadow_shadowmap2ddepthbuffer)
2209 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2211 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2212 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2213 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2217 // we have to set a viewport to clear anything in some renderpaths (D3D)
2218 R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize, 0, 0, 1.0, 1.0, 0.001f, 1.0f, NULL);
2219 R_SetViewport(&viewport);
2220 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2221 if (r_shadow_shadowmap2ddepthbuffer)
2222 GL_ColorMask(1, 1, 1, 1);
2224 GL_ColorMask(0, 0, 0, 0);
2225 switch (vid.renderpath)
2227 case RENDERPATH_GL11:
2228 case RENDERPATH_GL13:
2229 case RENDERPATH_GL20:
2230 case RENDERPATH_SOFT:
2231 case RENDERPATH_GLES1:
2232 case RENDERPATH_GLES2:
2233 GL_CullFace(r_refdef.view.cullface_back);
2235 case RENDERPATH_D3D9:
2236 case RENDERPATH_D3D10:
2237 case RENDERPATH_D3D11:
2238 // we invert the cull mode because we flip the projection matrix
2239 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2240 GL_CullFace(r_refdef.view.cullface_front);
2243 Vector4Set(clearcolor, 1, 1, 1, 1);
2244 if (r_shadow_shadowmap2ddepthbuffer)
2245 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2247 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2250 static void R_Shadow_SetShadowmapParametersForLight(qboolean noselfshadowpass)
2252 int size = rsurface.rtlight->shadowmapatlassidesize;
2253 float nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2254 float farclip = 1.0f;
2255 float bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2256 r_shadow_lightshadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
2257 r_shadow_lightshadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
2258 r_shadow_lightshadowmap_texturescale[2] = rsurface.rtlight->shadowmapatlasposition[0] + (noselfshadowpass ? size * 2 : 0);
2259 r_shadow_lightshadowmap_texturescale[3] = rsurface.rtlight->shadowmapatlasposition[1];
2260 r_shadow_lightshadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2261 r_shadow_lightshadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2262 r_shadow_lightshadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2263 r_shadow_lightshadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2264 if (r_shadow_shadowmap2ddepthbuffer)
2266 // completely different meaning than in depthtexture approach
2267 r_shadow_lightshadowmap_parameters[1] = 0;
2268 r_shadow_lightshadowmap_parameters[3] = -bias;
2272 static void R_Shadow_RenderMode_ShadowMap(int side, int size, int x, int y)
2274 float nearclip, farclip, bias;
2275 r_viewport_t viewport;
2277 float clearcolor[4];
2279 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_SHADOWMAP2D)
2281 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2283 R_Mesh_ResetTextureState();
2284 R_Shadow_RenderMode_Reset();
2285 if (r_shadow_shadowmap2ddepthbuffer)
2286 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2288 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2289 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2290 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2295 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2297 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2299 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
2300 R_SetViewport(&viewport);
2301 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2302 flipped = (side & 1) ^ (side >> 2);
2303 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2304 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2306 Vector4Set(clearcolor, 1,1,1,1);
2307 if (r_shadow_shadowmap2ddepthbuffer)
2308 GL_ColorMask(1,1,1,1);
2310 GL_ColorMask(0,0,0,0);
2311 switch(vid.renderpath)
2313 case RENDERPATH_GL11:
2314 case RENDERPATH_GL13:
2315 case RENDERPATH_GL20:
2316 case RENDERPATH_SOFT:
2317 case RENDERPATH_GLES1:
2318 case RENDERPATH_GLES2:
2319 GL_CullFace(r_refdef.view.cullface_back);
2321 case RENDERPATH_D3D9:
2322 case RENDERPATH_D3D10:
2323 case RENDERPATH_D3D11:
2324 // we invert the cull mode because we flip the projection matrix
2325 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2326 GL_CullFace(r_refdef.view.cullface_front);
2330 // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
2331 r_shadow_shadowmapside = side;
2334 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass)
2336 R_Mesh_ResetTextureState();
2339 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2340 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2341 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2342 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2345 R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
2346 R_Shadow_RenderMode_Reset();
2347 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2349 GL_DepthFunc(GL_EQUAL);
2350 // do global setup needed for the chosen lighting mode
2351 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2352 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2353 r_shadow_usingshadowmap2d = shadowmapping;
2354 r_shadow_rendermode = r_shadow_lightingrendermode;
2355 // only draw light where this geometry was already rendered AND the
2356 // stencil is 128 (values other than this mean shadow)
2358 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2360 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2363 static const unsigned short bboxelements[36] =
2373 static const float bboxpoints[8][3] =
2385 void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping)
2388 float vertex3f[8*3];
2389 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2390 // do global setup needed for the chosen lighting mode
2391 R_Shadow_RenderMode_Reset();
2392 r_shadow_rendermode = r_shadow_lightingrendermode;
2393 R_EntityMatrix(&identitymatrix);
2394 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2395 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2396 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
2397 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2399 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
2401 r_shadow_usingshadowmap2d = shadowmapping;
2403 // render the lighting
2404 R_SetupShader_DeferredLight(rsurface.rtlight);
2405 for (i = 0;i < 8;i++)
2406 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2407 GL_ColorMask(1,1,1,1);
2408 GL_DepthMask(false);
2409 GL_DepthRange(0, 1);
2410 GL_PolygonOffset(0, 0);
2412 GL_DepthFunc(GL_GREATER);
2413 GL_CullFace(r_refdef.view.cullface_back);
2414 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
2415 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2418 #define MAXBOUNCEGRIDSPLATSIZE 7
2419 #define MAXBOUNCEGRIDSPLATSIZE1 (MAXBOUNCEGRIDSPLATSIZE+1)
2421 // these are temporary data per-frame, sorted and performed in a more
2422 // cache-friendly order than the original photons
2423 typedef struct r_shadow_bouncegrid_splatpath_s
2429 vec_t splatintensity;
2430 int remainingsplats;
2432 r_shadow_bouncegrid_splatpath_t;
2434 static void R_Shadow_BounceGrid_AddSplatPath(vec3_t originalstart, vec3_t originalend, vec3_t color)
2444 r_shadow_bouncegrid_splatpath_t *path;
2446 // cull paths that fail R_CullBox in dynamic mode
2447 if (!r_shadow_bouncegrid_state.settings.staticmode
2448 && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
2450 vec3_t cullmins, cullmaxs;
2451 cullmins[0] = min(originalstart[0], originalend[0]) - r_shadow_bouncegrid_state.settings.spacing[0];
2452 cullmins[1] = min(originalstart[1], originalend[1]) - r_shadow_bouncegrid_state.settings.spacing[1];
2453 cullmins[2] = min(originalstart[2], originalend[2]) - r_shadow_bouncegrid_state.settings.spacing[2];
2454 cullmaxs[0] = max(originalstart[0], originalend[0]) + r_shadow_bouncegrid_state.settings.spacing[0];
2455 cullmaxs[1] = max(originalstart[1], originalend[1]) + r_shadow_bouncegrid_state.settings.spacing[1];
2456 cullmaxs[2] = max(originalstart[2], originalend[2]) + r_shadow_bouncegrid_state.settings.spacing[2];
2457 if (R_CullBox(cullmins, cullmaxs))
2461 // if the light path is going upward, reverse it - we always draw down.
2462 if (originalend[2] < originalstart[2])
2464 VectorCopy(originalend, start);
2465 VectorCopy(originalstart, end);
2469 VectorCopy(originalstart, start);
2470 VectorCopy(originalend, end);
2473 // transform to texture pixels
2474 start[0] = (start[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2475 start[1] = (start[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2476 start[2] = (start[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2477 end[0] = (end[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2478 end[1] = (end[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2479 end[2] = (end[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2481 // check if we need to grow the splatpaths array
2482 if (r_shadow_bouncegrid_state.maxsplatpaths <= r_shadow_bouncegrid_state.numsplatpaths)
2484 // double the limit, this will persist from frame to frame so we don't
2485 // make the same mistake each time
2486 r_shadow_bouncegrid_state.maxsplatpaths *= 2;
2487 if (r_shadow_bouncegrid_state.maxsplatpaths < 16384)
2488 r_shadow_bouncegrid_state.maxsplatpaths = 16384;
2489 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);
2492 // divide a series of splats along the length using the maximum axis
2493 VectorSubtract(end, start, diff);
2494 // pick the best axis to trace along
2496 if (diff[1]*diff[1] > diff[bestaxis]*diff[bestaxis])
2498 if (diff[2]*diff[2] > diff[bestaxis]*diff[bestaxis])
2500 len = fabs(diff[bestaxis]);
2502 numsplats = (int)(floor(len + 0.5f));
2504 numsplats = bound(0, numsplats, 1024);
2506 VectorSubtract(originalstart, originalend, originaldir);
2507 VectorNormalize(originaldir);
2509 path = r_shadow_bouncegrid_state.splatpaths + r_shadow_bouncegrid_state.numsplatpaths++;
2510 VectorCopy(start, path->point);
2511 VectorScale(diff, ilen, path->step);
2512 VectorCopy(color, path->splatcolor);
2513 VectorCopy(originaldir, path->splatdir);
2514 path->splatintensity = VectorLength(color);
2515 path->remainingsplats = numsplats;
2518 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
2520 qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
2527 // see if there are really any lights to render...
2528 if (enable && r_shadow_bouncegrid_static.integer)
2531 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2532 for (lightindex = 0;lightindex < range;lightindex++)
2534 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2535 if (!light || !(light->flags & flag))
2537 rtlight = &light->rtlight;
2538 // when static, we skip styled lights because they tend to change...
2539 if (rtlight->style > 0)
2541 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
2542 if (!VectorLength2(lightcolor))
2552 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
2554 qboolean s = r_shadow_bouncegrid_static.integer != 0;
2555 float spacing = s ? r_shadow_bouncegrid_static_spacing.value : r_shadow_bouncegrid_dynamic_spacing.value;
2556 float bounceminimumintensity = s ? r_shadow_bouncegrid_static_bounceminimumintensity.value : r_shadow_bouncegrid_dynamic_bounceminimumintensity.value;
2558 // prevent any garbage in alignment padded areas as we'll be using memcmp
2559 memset(settings, 0, sizeof(*settings));
2561 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
2562 settings->staticmode = s;
2563 settings->blur = r_shadow_bouncegrid_blur.integer != 0;
2564 settings->floatcolors = bound(0, r_shadow_bouncegrid_floatcolors.integer, 2);
2565 settings->lightpathsize = bound(1, r_shadow_bouncegrid_lightpathsize.integer, MAXBOUNCEGRIDSPLATSIZE);
2566 settings->bounceanglediffuse = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
2567 settings->directionalshading = (s ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_dynamic_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
2568 settings->dlightparticlemultiplier = s ? 0 : r_shadow_bouncegrid_dynamic_dlightparticlemultiplier.value;
2569 settings->hitmodels = s ? false : r_shadow_bouncegrid_dynamic_hitmodels.integer != 0;
2570 settings->includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
2571 settings->lightradiusscale = (s ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_dynamic_lightradiusscale.value);
2572 settings->maxbounce = (s ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_dynamic_maxbounce.integer);
2573 settings->particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
2574 settings->particleintensity = r_shadow_bouncegrid_particleintensity.value * (settings->directionalshading ? 4.0f : 1.0f) * 16384 / (spacing * spacing) / 262144.0f;
2575 settings->maxphotons = s ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_dynamic_maxphotons.integer;
2576 settings->energyperphoton = s ? r_shadow_bouncegrid_static_energyperphoton.value : r_shadow_bouncegrid_dynamic_energyperphoton.value;
2577 settings->spacing[0] = spacing;
2578 settings->spacing[1] = spacing;
2579 settings->spacing[2] = spacing;
2580 settings->stablerandom = r_shadow_bouncegrid_dynamic_stablerandom.integer;
2581 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
2582 settings->normalizevectors = r_shadow_bouncegrid_normalizevectors.integer != 0;
2584 // bound the values for sanity
2585 settings->maxphotons = bound(1, settings->maxphotons, 25000000);
2586 settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
2587 settings->maxbounce = bound(0, settings->maxbounce, 16);
2588 settings->spacing[0] = bound(1, settings->spacing[0], 512);
2589 settings->spacing[1] = bound(1, settings->spacing[1], 512);
2590 settings->spacing[2] = bound(1, settings->spacing[2], 512);
2592 // check if the ram requirements for blur would be excessive and disable it (increase lightpathsize to compensate)
2593 if (spacing < 32 && settings->blur)
2595 settings->blur = false;
2596 settings->lightpathsize += 2;
2600 static void R_Shadow_BounceGrid_UpdateSpacing(void)
2611 r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
2613 // get the spacing values
2614 spacing[0] = settings->spacing[0];
2615 spacing[1] = settings->spacing[1];
2616 spacing[2] = settings->spacing[2];
2617 ispacing[0] = 1.0f / spacing[0];
2618 ispacing[1] = 1.0f / spacing[1];
2619 ispacing[2] = 1.0f / spacing[2];
2621 // calculate texture size enclosing entire world bounds at the spacing
2622 if (r_refdef.scene.worldmodel)
2624 VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
2625 VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
2629 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
2630 VectorSet(maxs, 1048576.0f, 1048576.0f, 1048576.0f);
2632 VectorSubtract(maxs, mins, size);
2633 // now we can calculate the resolution we want
2634 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2635 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2636 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2637 // figure out the exact texture size (honoring power of 2 if required)
2638 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2639 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2640 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2641 if (vid.support.arb_texture_non_power_of_two)
2643 resolution[0] = c[0];
2644 resolution[1] = c[1];
2645 resolution[2] = c[2];
2649 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2650 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2651 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2653 size[0] = spacing[0] * resolution[0];
2654 size[1] = spacing[1] * resolution[1];
2655 size[2] = spacing[2] * resolution[2];
2657 // if dynamic we may or may not want to use the world bounds
2658 // if the dynamic size is smaller than the world bounds, use it instead
2659 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]))
2661 // we know the resolution we want
2662 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
2663 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
2664 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
2665 // now we can calculate the texture size (power of 2 if required)
2666 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2667 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2668 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2669 if (vid.support.arb_texture_non_power_of_two)
2671 resolution[0] = c[0];
2672 resolution[1] = c[1];
2673 resolution[2] = c[2];
2677 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2678 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2679 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2681 size[0] = spacing[0] * resolution[0];
2682 size[1] = spacing[1] * resolution[1];
2683 size[2] = spacing[2] * resolution[2];
2684 // center the rendering on the view
2685 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2686 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2687 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2690 // recalculate the maxs in case the resolution was not satisfactory
2691 VectorAdd(mins, size, maxs);
2693 // check if this changed the texture size
2694 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);
2695 r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
2696 VectorCopy(mins, r_shadow_bouncegrid_state.mins);
2697 VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
2698 VectorCopy(size, r_shadow_bouncegrid_state.size);
2699 VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
2700 VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
2701 VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
2703 // reallocate pixels for this update if needed...
2704 r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
2705 r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
2706 r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
2707 numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
2708 if (r_shadow_bouncegrid_state.numpixels != numpixels)
2710 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
2711 r_shadow_bouncegrid_state.highpixels = NULL;
2712 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2713 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2714 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2715 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2716 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2717 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2718 r_shadow_bouncegrid_state.numpixels = numpixels;
2721 // update the bouncegrid matrix to put it in the world properly
2722 memset(m, 0, sizeof(m));
2723 m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
2724 m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
2725 m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
2726 m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
2727 m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
2728 m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
2730 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
2733 // enumerate world rtlights and sum the overall amount of light in the world,
2734 // from that we can calculate a scaling factor to fairly distribute photons
2735 // to all the lights
2737 // this modifies rtlight->photoncolor and rtlight->photons
2738 static void R_Shadow_BounceGrid_AssignPhotons(r_shadow_bouncegrid_settings_t *settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
2740 float normalphotonscaling;
2741 float photonscaling;
2742 float photonintensity;
2743 float photoncount = 0.0f;
2744 float lightintensity;
2750 unsigned int lightindex;
2753 normalphotonscaling = 1.0f / max(0.0001f, settings->energyperphoton);
2754 for (lightindex = 0;lightindex < range2;lightindex++)
2756 if (lightindex < range)
2758 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2761 rtlight = &light->rtlight;
2762 VectorClear(rtlight->bouncegrid_photoncolor);
2763 rtlight->bouncegrid_photons = 0;
2764 rtlight->bouncegrid_hits = 0;
2765 rtlight->bouncegrid_traces = 0;
2766 rtlight->bouncegrid_effectiveradius = 0;
2767 if (!(light->flags & flag))
2769 if (settings->staticmode)
2771 // when static, we skip styled lights because they tend to change...
2772 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2775 else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
2780 rtlight = r_refdef.scene.lights[lightindex - range];
2781 VectorClear(rtlight->bouncegrid_photoncolor);
2782 rtlight->bouncegrid_photons = 0;
2783 rtlight->bouncegrid_hits = 0;
2784 rtlight->bouncegrid_traces = 0;
2785 rtlight->bouncegrid_effectiveradius = 0;
2787 // draw only visible lights (major speedup)
2788 radius = rtlight->radius * settings->lightradiusscale;
2789 cullmins[0] = rtlight->shadoworigin[0] - radius;
2790 cullmins[1] = rtlight->shadoworigin[1] - radius;
2791 cullmins[2] = rtlight->shadoworigin[2] - radius;
2792 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2793 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2794 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2795 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2796 if (!settings->staticmode)
2798 if (R_CullBox(cullmins, cullmaxs))
2800 if (r_refdef.scene.worldmodel
2801 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2802 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2804 if (w * VectorLength2(rtlight->color) == 0.0f)
2807 // a light that does not emit any light before style is applied, can be
2808 // skipped entirely (it may just be a corona)
2809 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2811 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2812 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2813 // skip lights that will emit no photons
2814 if (!VectorLength2(rtlight->bouncegrid_photoncolor))
2816 // shoot particles from this light
2817 // use a calculation for the number of particles that will not
2818 // vary with lightstyle, otherwise we get randomized particle
2819 // distribution, the seeded random is only consistent for a
2820 // consistent number of particles on this light...
2821 s = rtlight->radius;
2822 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2823 if (lightindex >= range)
2824 lightintensity *= settings->dlightparticlemultiplier;
2825 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2826 photoncount += rtlight->bouncegrid_photons;
2827 VectorScale(rtlight->bouncegrid_photoncolor, settings->particleintensity * settings->energyperphoton, rtlight->bouncegrid_photoncolor);
2828 // if the lightstyle happens to be off right now, we can skip actually
2829 // firing the photons, but we did have to count them in the total.
2830 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2831 // rtlight->bouncegrid_photons = 0;
2833 // the user provided an energyperphoton value which we try to use
2834 // if that results in too many photons to shoot this frame, then we cap it
2835 // which causes photons to appear/disappear from frame to frame, so we don't
2836 // like doing that in the typical case
2837 photonscaling = 1.0f;
2838 photonintensity = 1.0f;
2839 if (photoncount > settings->maxphotons)
2841 photonscaling = settings->maxphotons / photoncount;
2842 photonintensity = 1.0f / photonscaling;
2845 // modify the lights to reflect our computed scaling
2846 for (lightindex = 0; lightindex < range2; lightindex++)
2848 if (lightindex < range)
2850 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2853 rtlight = &light->rtlight;
2856 rtlight = r_refdef.scene.lights[lightindex - range];
2857 rtlight->bouncegrid_photons *= photonscaling;
2858 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2862 static int R_Shadow_BounceGrid_SplatPathCompare(const void *pa, const void *pb)
2864 r_shadow_bouncegrid_splatpath_t *a = (r_shadow_bouncegrid_splatpath_t *)pa;
2865 r_shadow_bouncegrid_splatpath_t *b = (r_shadow_bouncegrid_splatpath_t *)pb;
2866 // we only really care about sorting by Z
2867 if (a->point[2] < b->point[2])
2869 if (a->point[2] > b->point[2])
2874 static void R_Shadow_BounceGrid_ClearPixels(void)
2876 // clear the highpixels array we'll be accumulating into
2877 if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2878 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2879 if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2880 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2881 r_shadow_bouncegrid_state.highpixels_index = 0;
2882 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2883 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2886 static void R_Shadow_BounceGrid_PerformSplats(void)
2888 int splatsize = r_shadow_bouncegrid_state.settings.lightpathsize;
2889 int splatsize1 = splatsize + 1;
2890 r_shadow_bouncegrid_splatpath_t *splatpaths = r_shadow_bouncegrid_state.splatpaths;
2891 r_shadow_bouncegrid_splatpath_t *splatpath;
2892 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2893 int numsplatpaths = r_shadow_bouncegrid_state.numsplatpaths;
2899 float texlerp[MAXBOUNCEGRIDSPLATSIZE1][3];
2900 float splatcolor[32];
2901 float boxweight = 1.0f / (splatsize * splatsize * splatsize);
2904 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2905 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2909 // hush warnings about uninitialized data - pixelbands doesn't change but...
2910 memset(splatcolor, 0, sizeof(splatcolor));
2912 // we use this a lot, so get a local copy
2913 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2915 // sort the splats before we execute them, to reduce cache misses
2916 if (r_shadow_bouncegrid_sortlightpaths.integer)
2917 qsort(splatpaths, numsplatpaths, sizeof(*splatpaths), R_Shadow_BounceGrid_SplatPathCompare);
2919 // the middle row/column/layer of each splat are full intensity
2920 for (step = 1;step < splatsize;step++)
2921 VectorSet(texlerp[step], 1.0f, 1.0f, 1.0f);
2923 splatpath = splatpaths;
2924 for (splatindex = 0;splatindex < numsplatpaths;splatindex++, splatpath++)
2926 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2927 // accumulate average shotcolor
2928 VectorCopy(splatpath->splatdir, dir);
2929 splatcolor[ 0] = splatpath->splatcolor[0];
2930 splatcolor[ 1] = splatpath->splatcolor[1];
2931 splatcolor[ 2] = splatpath->splatcolor[2];
2932 splatcolor[ 3] = 0.0f;
2935 // store bentnormal in case the shader has a use for it,
2936 // bentnormal is an intensity-weighted average of the directions,
2937 // and will be normalized on conversion to texture pixels.
2938 splatcolor[ 4] = dir[0] * splatpath->splatintensity;
2939 splatcolor[ 5] = dir[1] * splatpath->splatintensity;
2940 splatcolor[ 6] = dir[2] * splatpath->splatintensity;
2941 splatcolor[ 7] = splatpath->splatintensity;
2942 // for each color component (R, G, B) calculate the amount that a
2943 // direction contributes
2944 splatcolor[ 8] = splatcolor[0] * max(0.0f, dir[0]);
2945 splatcolor[ 9] = splatcolor[0] * max(0.0f, dir[1]);
2946 splatcolor[10] = splatcolor[0] * max(0.0f, dir[2]);
2947 splatcolor[11] = 0.0f;
2948 splatcolor[12] = splatcolor[1] * max(0.0f, dir[0]);
2949 splatcolor[13] = splatcolor[1] * max(0.0f, dir[1]);
2950 splatcolor[14] = splatcolor[1] * max(0.0f, dir[2]);
2951 splatcolor[15] = 0.0f;
2952 splatcolor[16] = splatcolor[2] * max(0.0f, dir[0]);
2953 splatcolor[17] = splatcolor[2] * max(0.0f, dir[1]);
2954 splatcolor[18] = splatcolor[2] * max(0.0f, dir[2]);
2955 splatcolor[19] = 0.0f;
2956 // and do the same for negative directions
2957 splatcolor[20] = splatcolor[0] * max(0.0f, -dir[0]);
2958 splatcolor[21] = splatcolor[0] * max(0.0f, -dir[1]);
2959 splatcolor[22] = splatcolor[0] * max(0.0f, -dir[2]);
2960 splatcolor[23] = 0.0f;
2961 splatcolor[24] = splatcolor[1] * max(0.0f, -dir[0]);
2962 splatcolor[25] = splatcolor[1] * max(0.0f, -dir[1]);
2963 splatcolor[26] = splatcolor[1] * max(0.0f, -dir[2]);
2964 splatcolor[27] = 0.0f;
2965 splatcolor[28] = splatcolor[2] * max(0.0f, -dir[0]);
2966 splatcolor[29] = splatcolor[2] * max(0.0f, -dir[1]);
2967 splatcolor[30] = splatcolor[2] * max(0.0f, -dir[2]);
2968 splatcolor[31] = 0.0f;
2970 // calculate the number of steps we need to traverse this distance
2971 VectorCopy(splatpath->point, steppos);
2972 VectorCopy(splatpath->step, stepdelta);
2973 numsteps = splatpath->remainingsplats;
2974 for (step = 0;step < numsteps;step++)
2976 r_refdef.stats[r_stat_bouncegrid_splats]++;
2977 // figure out the min corner of the pixels we'll need to update
2978 texcorner[0] = steppos[0] - (splatsize1 * 0.5f);
2979 texcorner[1] = steppos[1] - (splatsize1 * 0.5f);
2980 texcorner[2] = steppos[2] - (splatsize1 * 0.5f);
2981 tex[0] = (int)floor(texcorner[0]);
2982 tex[1] = (int)floor(texcorner[1]);
2983 tex[2] = (int)floor(texcorner[2]);
2984 // only update if it is within reasonable bounds
2988 && tex[0] < resolution[0] - splatsize1
2989 && tex[1] < resolution[1] - splatsize1
2990 && tex[2] < resolution[2] - splatsize1)
2992 // it is within bounds... do the real work now
2995 // calculate the antialiased box edges
2996 texlerp[splatsize][0] = texcorner[0] - tex[0];
2997 texlerp[splatsize][1] = texcorner[1] - tex[1];
2998 texlerp[splatsize][2] = texcorner[2] - tex[2];
2999 texlerp[0][0] = 1.0f - texlerp[splatsize][0];
3000 texlerp[0][1] = 1.0f - texlerp[splatsize][1];
3001 texlerp[0][2] = 1.0f - texlerp[splatsize][2];
3003 // accumulate light onto the pixels
3004 for (zi = 0;zi < splatsize1;zi++)
3006 for (yi = 0;yi < splatsize1;yi++)
3008 int index = ((tex[2]+zi)*resolution[1]+tex[1]+yi)*resolution[0]+tex[0];
3009 for (xi = 0;xi < splatsize1;xi++, index++)
3011 float w = texlerp[xi][0]*texlerp[yi][1]*texlerp[zi][2] * boxweight;
3013 float *p = highpixels + 4 * index + band * pixelsperband * 4;
3014 for (;band < pixelbands;band++, p += pixelsperband * 4)
3016 // add to the pixel color
3017 p[0] += splatcolor[band*4+0] * w;
3018 p[1] += splatcolor[band*4+1] * w;
3019 p[2] += splatcolor[band*4+2] * w;
3020 p[3] += splatcolor[band*4+3] * w;
3026 VectorAdd(steppos, stepdelta, steppos);
3031 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
3033 const float *inpixel;
3035 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
3038 unsigned int x, y, z;
3039 unsigned int resolution[3];
3040 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3041 for (pixelband = 0;pixelband < pixelbands;pixelband++)
3043 for (z = 1;z < resolution[2]-1;z++)
3045 for (y = 1;y < resolution[1]-1;y++)
3048 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3049 inpixel = inpixels + 4*index;
3050 outpixel = outpixels + 4*index;
3051 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
3053 outpixel[0] = (inpixel[0] + inpixel[ off] + inpixel[0-off]) * (1.0f / 3.0);
3054 outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
3055 outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
3056 outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
3063 static void R_Shadow_BounceGrid_BlurPixels(void)
3066 unsigned int resolution[3];
3068 if (!r_shadow_bouncegrid_state.settings.blur)
3071 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3073 pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3074 pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
3075 pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3076 pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
3079 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
3081 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
3083 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
3085 // toggle the state, highpixels now points to pixels[3] result
3086 r_shadow_bouncegrid_state.highpixels_index ^= 1;
3087 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3090 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
3092 int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
3093 unsigned char *pixelsbgra8 = NULL;
3094 unsigned char *pixelbgra8;
3095 unsigned short *pixelsrgba16f = NULL;
3096 unsigned short *pixelrgba16f;
3097 float *pixelsrgba32f = NULL;
3098 float *highpixels = r_shadow_bouncegrid_state.highpixels;
3101 unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
3102 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
3103 unsigned int pixelband;
3104 unsigned int x, y, z;
3105 unsigned int index, bandindex;
3106 unsigned int resolution[3];
3108 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3110 if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
3112 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3113 r_shadow_bouncegrid_state.texture = NULL;
3116 // if bentnormals exist, we need to normalize and bias them for the shader
3120 for (z = 0;z < resolution[2]-1;z++)
3122 for (y = 0;y < resolution[1]-1;y++)
3125 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3126 highpixel = highpixels + 4*index;
3127 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3129 // only convert pixels that were hit by photons
3130 if (highpixel[3] != 0.0f)
3131 VectorNormalize(highpixel);
3132 VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
3133 highpixel[pixelsperband * 4 + 3] = 1.0f;
3139 // start by clearing the pixels array - we won't be writing to all of it
3141 // then process only the pixels that have at least some color, skipping
3142 // the higher bands for speed on pixels that are black
3143 switch (floatcolors)
3146 if (r_shadow_bouncegrid_state.u8pixels == NULL)
3147 r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
3148 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
3149 for (pixelband = 0;pixelband < pixelbands;pixelband++)
3152 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
3154 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
3156 for (z = 1;z < resolution[2]-1;z++)
3158 for (y = 1;y < resolution[1]-1;y++)
3162 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3163 highpixel = highpixels + 4*index;
3164 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3166 // only convert pixels that were hit by photons
3167 if (VectorLength2(highpixel))
3169 // normalize the bentnormal now
3172 VectorNormalize(highpixel + pixelsperband * 4);
3173 highpixel[pixelsperband * 4 + 3] = 1.0f;
3175 // process all of the pixelbands for this pixel
3176 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3178 pixelbgra8 = pixelsbgra8 + 4*bandindex;
3179 bandpixel = highpixels + 4*bandindex;
3180 c[0] = (int)(bandpixel[0]*256.0f);
3181 c[1] = (int)(bandpixel[1]*256.0f);
3182 c[2] = (int)(bandpixel[2]*256.0f);
3183 c[3] = (int)(bandpixel[3]*256.0f);
3184 pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
3185 pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
3186 pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
3187 pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
3194 if (!r_shadow_bouncegrid_state.createtexture)
3195 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3197 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);
3200 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
3201 r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3202 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
3203 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3204 for (z = 1;z < resolution[2]-1;z++)
3206 for (y = 1;y < resolution[1]-1;y++)
3210 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3211 highpixel = highpixels + 4*index;
3212 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3214 // only convert pixels that were hit by photons
3215 if (VectorLength2(highpixel))
3217 // process all of the pixelbands for this pixel
3218 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3220 // time to have fun with IEEE 754 bit hacking...
3223 unsigned int raw[4];
3225 pixelrgba16f = pixelsrgba16f + 4*bandindex;
3226 bandpixel = highpixels + 4*bandindex;
3227 VectorCopy4(bandpixel, u.f);
3228 VectorCopy4(u.raw, c);
3229 // this math supports negative numbers, snaps denormals to zero
3230 //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
3231 //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
3232 //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
3233 //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
3234 // this math does not support negative
3235 pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
3236 pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
3237 pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
3238 pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
3245 if (!r_shadow_bouncegrid_state.createtexture)
3246 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3248 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);
3251 // our native format happens to match, so this is easy.
3252 pixelsrgba32f = highpixels;
3254 if (!r_shadow_bouncegrid_state.createtexture)
3255 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3257 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);
3261 r_shadow_bouncegrid_state.lastupdatetime = realtime;
3264 static void R_Shadow_BounceGrid_TracePhotons(r_shadow_bouncegrid_settings_t settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
3266 vec3_t bouncerandom[10];
3269 int hitsupercontentsmask;
3270 int skipsupercontentsmask;
3274 float bounceminimumintensity2;
3276 //trace_t cliptrace2;
3277 //trace_t cliptrace3;
3278 unsigned int lightindex;
3280 randomseed_t randomseed;
3282 vec3_t baseshotcolor;
3297 // compute a seed for the unstable random modes
3298 memset(&rseed, 0, sizeof(rseed));
3300 Math_RandomSeed_FromInts(&randomseed, rseed.s[0], rseed.s[1], rseed.s[2], rseed.s[3]);
3301 seed = rseed.s[0] ^ rseed.s[1] ^ rseed.s[2] ^ rseed.s[3];
3303 r_shadow_bouncegrid_state.numsplatpaths = 0;
3305 // figure out what we want to interact with
3306 if (settings.hitmodels)
3307 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;// | SUPERCONTENTS_LIQUIDSMASK;
3309 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
3310 skipsupercontentsmask = SUPERCONTENTS_SKY; // this allows the e1m5 sky shadow to work by ignoring the sky surfaces
3311 maxbounce = settings.maxbounce;
3313 for (lightindex = 0;lightindex < range2;lightindex++)
3315 if (lightindex < range)
3317 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3320 rtlight = &light->rtlight;
3323 rtlight = r_refdef.scene.lights[lightindex - range];
3324 // note that this code used to keep track of residual photons and
3325 // distribute them evenly to achieve exactly a desired photon count,
3326 // but that caused unwanted flickering in dynamic mode
3327 shootparticles = (int)floor(rtlight->bouncegrid_photons);
3328 // skip if we won't be shooting any photons
3329 if (!shootparticles)
3331 radius = rtlight->radius * settings.lightradiusscale;
3332 //s = settings.particleintensity / shootparticles;
3333 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
3334 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
3335 if (VectorLength2(baseshotcolor) <= 0.0f)
3337 r_refdef.stats[r_stat_bouncegrid_lights]++;
3338 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
3339 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
3340 bounceminimumintensity2 = VectorLength(baseshotcolor) * settings.bounceminimumintensity2;
3342 // for stablerandom we start the RNG with the position of the light
3343 if (settings.stablerandom > 0)
3351 u.f[0] = rtlight->shadoworigin[0];
3352 u.f[1] = rtlight->shadoworigin[1];
3353 u.f[2] = rtlight->shadoworigin[2];
3355 switch (settings.stablerandom)
3360 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3];
3363 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3]);
3368 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
3370 VectorCopy(baseshotcolor, shotcolor);
3371 VectorCopy(rtlight->shadoworigin, clipstart);
3372 switch (settings.stablerandom)
3376 VectorRandom(clipend);
3377 if (settings.bounceanglediffuse)
3379 // we want random to be stable, so we still have to do all the random we would have done
3380 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3381 VectorRandom(bouncerandom[bouncecount]);
3386 VectorCheeseRandom(seed, clipend);
3387 if (settings.bounceanglediffuse)
3389 // we want random to be stable, so we still have to do all the random we would have done
3390 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3391 VectorCheeseRandom(seed, bouncerandom[bouncecount]);
3396 VectorLehmerRandom(&randomseed, clipend);
3397 if (settings.bounceanglediffuse)
3399 // we want random to be stable, so we still have to do all the random we would have done
3400 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3401 VectorLehmerRandom(&randomseed, bouncerandom[bouncecount]);
3406 // we want a uniform distribution spherically, not merely within the sphere
3407 if (settings.normalizevectors)
3408 VectorNormalize(clipend);
3410 VectorMA(clipstart, radius, clipend, clipend);
3411 for (bouncecount = 0;;bouncecount++)
3413 r_refdef.stats[r_stat_bouncegrid_traces]++;
3414 rtlight->bouncegrid_traces++;
3415 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
3416 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
3417 if (settings.staticmode || settings.stablerandom <= 0)
3419 // static mode fires a LOT of rays but none of them are identical, so they are not cached
3420 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
3421 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);
3425 // dynamic mode fires many rays and most will match the cache from the previous frame
3426 cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask, skipsupercontentsmask);
3428 if (bouncecount > 0 || settings.includedirectlighting)
3431 VectorCopy(cliptrace.endpos, hitpos);
3432 R_Shadow_BounceGrid_AddSplatPath(clipstart, hitpos, shotcolor);
3434 s = VectorDistance(rtlight->shadoworigin, cliptrace.endpos);
3435 if (rtlight->bouncegrid_effectiveradius < s)
3436 rtlight->bouncegrid_effectiveradius = s;
3437 if (cliptrace.fraction >= 1.0f)
3439 r_refdef.stats[r_stat_bouncegrid_hits]++;
3440 rtlight->bouncegrid_hits++;
3441 if (bouncecount >= maxbounce)
3443 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
3444 // also clamp the resulting color to never add energy, even if the user requests extreme values
3445 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
3446 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
3448 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
3449 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
3450 surfcolor[0] = min(surfcolor[0], 1.0f);
3451 surfcolor[1] = min(surfcolor[1], 1.0f);
3452 surfcolor[2] = min(surfcolor[2], 1.0f);
3453 VectorMultiply(shotcolor, surfcolor, shotcolor);
3454 if (VectorLength2(shotcolor) <= bounceminimumintensity2)
3456 r_refdef.stats[r_stat_bouncegrid_bounces]++;
3457 if (settings.bounceanglediffuse)
3459 // random direction, primarily along plane normal
3460 s = VectorDistance(cliptrace.endpos, clipend);
3461 VectorMA(cliptrace.plane.normal, 0.95f, bouncerandom[bouncecount], clipend);
3462 VectorNormalize(clipend);
3463 VectorScale(clipend, s, clipend);
3467 // reflect the remaining portion of the line across plane normal
3468 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
3469 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
3471 // calculate the new line start and end
3472 VectorCopy(cliptrace.endpos, clipstart);
3473 VectorAdd(clipstart, clipend, clipend);
3479 void R_Shadow_UpdateBounceGridTexture(void)
3481 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3482 r_shadow_bouncegrid_settings_t settings;
3483 qboolean enable = false;
3484 qboolean settingschanged;
3485 unsigned int range; // number of world lights
3486 unsigned int range1; // number of dynamic lights (or zero if disabled)
3487 unsigned int range2; // range+range1
3489 enable = R_Shadow_BounceGrid_CheckEnable(flag);
3491 R_Shadow_BounceGrid_GenerateSettings(&settings);
3493 // changing intensity does not require an update
3494 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
3496 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
3498 // when settings change, we free everything as it is just simpler that way.
3499 if (settingschanged || !enable)
3501 // not enabled, make sure we free anything we don't need anymore.
3502 if (r_shadow_bouncegrid_state.texture)
3504 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3505 r_shadow_bouncegrid_state.texture = NULL;
3507 r_shadow_bouncegrid_state.highpixels = NULL;
3508 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
3509 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
3510 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
3511 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
3512 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
3513 r_shadow_bouncegrid_state.maxsplatpaths = 0;
3514 r_shadow_bouncegrid_state.numpixels = 0;
3515 r_shadow_bouncegrid_state.directional = false;
3521 // if all the settings seem identical to the previous update, return
3522 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
3525 // store the new settings
3526 r_shadow_bouncegrid_state.settings = settings;
3528 R_Shadow_BounceGrid_UpdateSpacing();
3530 // get the range of light numbers we'll be looping over:
3531 // range = static lights
3532 // range1 = dynamic lights (optional)
3533 // range2 = range + range1
3534 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3535 range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
3536 range2 = range + range1;
3538 // calculate weighting factors for distributing photons among the lights
3539 R_Shadow_BounceGrid_AssignPhotons(&settings, range, range1, range2, flag);
3541 // trace the photons from lights and accumulate illumination
3542 R_Shadow_BounceGrid_TracePhotons(settings, range, range1, range2, flag);
3544 // clear the texture
3545 R_Shadow_BounceGrid_ClearPixels();
3547 // accumulate the light splatting into texture
3548 R_Shadow_BounceGrid_PerformSplats();
3550 // apply a mild blur filter to the texture
3551 R_Shadow_BounceGrid_BlurPixels();
3553 // convert the pixels to lower precision and upload the texture
3554 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
3556 // after we compute the static lighting we don't need to keep the highpixels array around
3557 if (settings.staticmode)
3559 r_shadow_bouncegrid_state.highpixels = NULL;
3560 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
3561 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
3562 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
3563 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
3564 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
3565 r_shadow_bouncegrid_state.maxsplatpaths = 0;
3569 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
3571 R_Shadow_RenderMode_Reset();
3572 GL_BlendFunc(GL_ONE, GL_ONE);
3573 GL_DepthRange(0, 1);
3574 GL_DepthTest(r_showshadowvolumes.integer < 2);
3575 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
3576 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
3577 GL_CullFace(GL_NONE);
3578 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
3581 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
3583 R_Shadow_RenderMode_Reset();
3584 GL_BlendFunc(GL_ONE, GL_ONE);
3585 GL_DepthRange(0, 1);
3586 GL_DepthTest(r_showlighting.integer < 2);
3587 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
3589 GL_DepthFunc(GL_EQUAL);
3590 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
3591 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
3594 void R_Shadow_RenderMode_End(void)
3596 R_Shadow_RenderMode_Reset();
3597 R_Shadow_RenderMode_ActiveLight(NULL);
3599 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3600 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3603 int bboxedges[12][2] =
3622 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
3624 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
3626 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
3627 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
3628 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
3629 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
3632 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
3633 return true; // invisible
3634 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
3635 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
3636 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
3637 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
3638 r_refdef.stats[r_stat_lights_scissored]++;
3642 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
3645 const float *vertex3f;
3646 const float *normal3f;
3648 float dist, dot, distintensity, shadeintensity, v[3], n[3];
3649 switch (r_shadow_rendermode)
3651 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3652 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3653 if (VectorLength2(diffusecolor) > 0)
3655 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)
3657 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3658 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3659 if ((dot = DotProduct(n, v)) < 0)
3661 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3662 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
3665 VectorCopy(ambientcolor, color4f);
3666 if (r_refdef.fogenabled)
3669 f = RSurf_FogVertex(vertex3f);
3670 VectorScale(color4f, f, color4f);
3677 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3679 VectorCopy(ambientcolor, color4f);
3680 if (r_refdef.fogenabled)
3683 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3684 f = RSurf_FogVertex(vertex3f);
3685 VectorScale(color4f + 4*i, f, color4f);
3691 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3692 if (VectorLength2(diffusecolor) > 0)
3694 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)
3696 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3697 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3699 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3700 if ((dot = DotProduct(n, v)) < 0)
3702 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3703 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3704 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3705 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3709 color4f[0] = ambientcolor[0] * distintensity;
3710 color4f[1] = ambientcolor[1] * distintensity;
3711 color4f[2] = ambientcolor[2] * distintensity;
3713 if (r_refdef.fogenabled)
3716 f = RSurf_FogVertex(vertex3f);
3717 VectorScale(color4f, f, color4f);
3721 VectorClear(color4f);
3727 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3729 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3730 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3732 color4f[0] = ambientcolor[0] * distintensity;
3733 color4f[1] = ambientcolor[1] * distintensity;
3734 color4f[2] = ambientcolor[2] * distintensity;
3735 if (r_refdef.fogenabled)
3738 f = RSurf_FogVertex(vertex3f);
3739 VectorScale(color4f, f, color4f);
3743 VectorClear(color4f);
3748 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3749 if (VectorLength2(diffusecolor) > 0)
3751 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)
3753 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3754 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3756 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3757 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3758 if ((dot = DotProduct(n, v)) < 0)
3760 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3761 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3762 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3763 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3767 color4f[0] = ambientcolor[0] * distintensity;
3768 color4f[1] = ambientcolor[1] * distintensity;
3769 color4f[2] = ambientcolor[2] * distintensity;
3771 if (r_refdef.fogenabled)
3774 f = RSurf_FogVertex(vertex3f);
3775 VectorScale(color4f, f, color4f);
3779 VectorClear(color4f);
3785 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3787 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3788 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3790 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3791 color4f[0] = ambientcolor[0] * distintensity;
3792 color4f[1] = ambientcolor[1] * distintensity;
3793 color4f[2] = ambientcolor[2] * distintensity;
3794 if (r_refdef.fogenabled)
3797 f = RSurf_FogVertex(vertex3f);
3798 VectorScale(color4f, f, color4f);
3802 VectorClear(color4f);
3812 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3814 // used to display how many times a surface is lit for level design purposes
3815 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3816 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3820 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
3822 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3823 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
3827 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3834 int newnumtriangles;
3838 int maxtriangles = 1024;
3839 int newelements[1024*3];
3840 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3841 for (renders = 0;renders < 4;renders++)
3846 newnumtriangles = 0;
3848 // due to low fillrate on the cards this vertex lighting path is
3849 // designed for, we manually cull all triangles that do not
3850 // contain a lit vertex
3851 // this builds batches of triangles from multiple surfaces and
3852 // renders them at once
3853 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3855 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3857 if (newnumtriangles)
3859 newfirstvertex = min(newfirstvertex, e[0]);
3860 newlastvertex = max(newlastvertex, e[0]);
3864 newfirstvertex = e[0];
3865 newlastvertex = e[0];
3867 newfirstvertex = min(newfirstvertex, e[1]);
3868 newlastvertex = max(newlastvertex, e[1]);
3869 newfirstvertex = min(newfirstvertex, e[2]);
3870 newlastvertex = max(newlastvertex, e[2]);
3876 if (newnumtriangles >= maxtriangles)
3878 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3879 newnumtriangles = 0;
3885 if (newnumtriangles >= 1)
3887 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3890 // if we couldn't find any lit triangles, exit early
3893 // now reduce the intensity for the next overbright pass
3894 // we have to clamp to 0 here incase the drivers have improper
3895 // handling of negative colors
3896 // (some old drivers even have improper handling of >1 color)
3898 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3900 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3902 c[0] = max(0, c[0] - 1);
3903 c[1] = max(0, c[1] - 1);
3904 c[2] = max(0, c[2] - 1);
3916 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
3918 // OpenGL 1.1 path (anything)
3919 float ambientcolorbase[3], diffusecolorbase[3];
3920 float ambientcolorpants[3], diffusecolorpants[3];
3921 float ambientcolorshirt[3], diffusecolorshirt[3];
3922 const float *surfacecolor = rsurface.texture->dlightcolor;
3923 const float *surfacepants = rsurface.colormap_pantscolor;
3924 const float *surfaceshirt = rsurface.colormap_shirtcolor;
3925 rtexture_t *basetexture = rsurface.texture->basetexture;
3926 rtexture_t *pantstexture = rsurface.texture->pantstexture;
3927 rtexture_t *shirttexture = rsurface.texture->shirttexture;
3928 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3929 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3930 ambientscale *= 2 * r_refdef.view.colorscale;
3931 diffusescale *= 2 * r_refdef.view.colorscale;
3932 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3933 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3934 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3935 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3936 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3937 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
3938 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3939 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
3940 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3941 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
3942 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
3943 R_Mesh_TexBind(0, basetexture);
3944 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
3945 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
3946 switch(r_shadow_rendermode)
3948 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3949 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
3950 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3951 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3952 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3954 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3955 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
3956 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
3957 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
3958 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3960 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3961 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
3962 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3963 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3964 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3966 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3971 //R_Mesh_TexBind(0, basetexture);
3972 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
3975 R_Mesh_TexBind(0, pantstexture);
3976 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
3980 R_Mesh_TexBind(0, shirttexture);
3981 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
3985 extern cvar_t gl_lightmaps;
3986 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3988 float ambientscale, diffusescale, specularscale;
3990 float lightcolor[3];
3991 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
3992 ambientscale = rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient;
3993 diffusescale = rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient);
3994 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3995 if (!r_shadow_usenormalmap.integer)
3997 ambientscale += 1.0f * diffusescale;
4001 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
4003 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
4006 VectorNegate(lightcolor, lightcolor);
4007 GL_BlendEquationSubtract(true);
4009 RSurf_SetupDepthAndCulling();
4010 switch (r_shadow_rendermode)
4012 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
4013 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
4014 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
4016 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
4017 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
4019 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
4020 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
4021 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
4022 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
4023 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
4026 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
4030 GL_BlendEquationSubtract(false);
4033 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)
4035 matrix4x4_t tempmatrix = *matrix;
4036 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
4038 // if this light has been compiled before, free the associated data
4039 R_RTLight_Uncompile(rtlight);
4041 // clear it completely to avoid any lingering data
4042 memset(rtlight, 0, sizeof(*rtlight));
4044 // copy the properties
4045 rtlight->matrix_lighttoworld = tempmatrix;
4046 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
4047 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
4048 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
4049 VectorCopy(color, rtlight->color);
4050 rtlight->cubemapname[0] = 0;
4051 if (cubemapname && cubemapname[0])
4052 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
4053 rtlight->shadow = shadow;
4054 rtlight->corona = corona;
4055 rtlight->style = style;
4056 rtlight->isstatic = isstatic;
4057 rtlight->coronasizescale = coronasizescale;
4058 rtlight->ambientscale = ambientscale;
4059 rtlight->diffusescale = diffusescale;
4060 rtlight->specularscale = specularscale;
4061 rtlight->flags = flags;
4063 // compute derived data
4064 //rtlight->cullradius = rtlight->radius;
4065 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
4066 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
4067 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
4068 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
4069 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
4070 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
4071 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
4074 // compiles rtlight geometry
4075 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
4076 void R_RTLight_Compile(rtlight_t *rtlight)
4079 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
4080 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
4081 entity_render_t *ent = r_refdef.scene.worldentity;
4082 dp_model_t *model = r_refdef.scene.worldmodel;
4083 unsigned char *data;
4086 // compile the light
4087 rtlight->compiled = true;
4088 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
4089 rtlight->static_numleafs = 0;
4090 rtlight->static_numleafpvsbytes = 0;
4091 rtlight->static_leaflist = NULL;
4092 rtlight->static_leafpvs = NULL;
4093 rtlight->static_numsurfaces = 0;
4094 rtlight->static_surfacelist = NULL;
4095 rtlight->static_shadowmap_receivers = 0x3F;
4096 rtlight->static_shadowmap_casters = 0x3F;
4097 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
4098 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
4099 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
4100 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
4101 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
4102 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
4104 if (model && model->GetLightInfo)
4106 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
4107 r_shadow_compilingrtlight = rtlight;
4108 R_FrameData_SetMark();
4109 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);
4110 R_FrameData_ReturnToMark();
4111 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
4112 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
4113 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
4114 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
4115 rtlight->static_numsurfaces = numsurfaces;
4116 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
4117 rtlight->static_numleafs = numleafs;
4118 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
4119 rtlight->static_numleafpvsbytes = numleafpvsbytes;
4120 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
4121 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
4122 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
4123 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
4124 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
4125 if (rtlight->static_numsurfaces)
4126 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
4127 if (rtlight->static_numleafs)
4128 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
4129 if (rtlight->static_numleafpvsbytes)
4130 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
4131 if (rtlight->static_numshadowtrispvsbytes)
4132 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
4133 if (rtlight->static_numlighttrispvsbytes)
4134 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
4135 R_FrameData_SetMark();
4136 switch (rtlight->shadowmode)
4138 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4139 if (model->CompileShadowMap && rtlight->shadow)
4140 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
4143 if (model->CompileShadowVolume && rtlight->shadow)
4144 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
4147 R_FrameData_ReturnToMark();
4148 // now we're done compiling the rtlight
4149 r_shadow_compilingrtlight = NULL;
4153 // use smallest available cullradius - box radius or light radius
4154 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
4155 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
4157 shadowzpasstris = 0;
4158 if (rtlight->static_meshchain_shadow_zpass)
4159 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
4160 shadowzpasstris += mesh->numtriangles;
4162 shadowzfailtris = 0;
4163 if (rtlight->static_meshchain_shadow_zfail)
4164 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
4165 shadowzfailtris += mesh->numtriangles;
4168 if (rtlight->static_numlighttrispvsbytes)
4169 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
4170 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
4174 if (rtlight->static_numshadowtrispvsbytes)
4175 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
4176 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
4179 if (developer_extra.integer)
4180 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);
4183 void R_RTLight_Uncompile(rtlight_t *rtlight)
4185 if (rtlight->compiled)
4187 if (rtlight->static_meshchain_shadow_zpass)
4188 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
4189 rtlight->static_meshchain_shadow_zpass = NULL;
4190 if (rtlight->static_meshchain_shadow_zfail)
4191 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
4192 rtlight->static_meshchain_shadow_zfail = NULL;
4193 if (rtlight->static_meshchain_shadow_shadowmap)
4194 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
4195 rtlight->static_meshchain_shadow_shadowmap = NULL;
4196 // these allocations are grouped
4197 if (rtlight->static_surfacelist)
4198 Mem_Free(rtlight->static_surfacelist);
4199 rtlight->static_numleafs = 0;
4200 rtlight->static_numleafpvsbytes = 0;
4201 rtlight->static_leaflist = NULL;
4202 rtlight->static_leafpvs = NULL;
4203 rtlight->static_numsurfaces = 0;
4204 rtlight->static_surfacelist = NULL;
4205 rtlight->static_numshadowtrispvsbytes = 0;
4206 rtlight->static_shadowtrispvs = NULL;
4207 rtlight->static_numlighttrispvsbytes = 0;
4208 rtlight->static_lighttrispvs = NULL;
4209 rtlight->compiled = false;
4213 void R_Shadow_UncompileWorldLights(void)
4217 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4218 for (lightindex = 0;lightindex < range;lightindex++)
4220 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4223 R_RTLight_Uncompile(&light->rtlight);
4227 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
4231 // reset the count of frustum planes
4232 // see rtlight->cached_frustumplanes definition for how much this array
4234 rtlight->cached_numfrustumplanes = 0;
4236 if (r_trippy.integer)
4239 // haven't implemented a culling path for ortho rendering
4240 if (!r_refdef.view.useperspective)
4242 // check if the light is on screen and copy the 4 planes if it is
4243 for (i = 0;i < 4;i++)
4244 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4247 for (i = 0;i < 4;i++)
4248 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4253 // generate a deformed frustum that includes the light origin, this is
4254 // used to cull shadow casting surfaces that can not possibly cast a
4255 // shadow onto the visible light-receiving surfaces, which can be a
4258 // if the light origin is onscreen the result will be 4 planes exactly
4259 // if the light origin is offscreen on only one axis the result will
4260 // be exactly 5 planes (split-side case)
4261 // if the light origin is offscreen on two axes the result will be
4262 // exactly 4 planes (stretched corner case)
4263 for (i = 0;i < 4;i++)
4265 // quickly reject standard frustum planes that put the light
4266 // origin outside the frustum
4267 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4270 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4272 // if all the standard frustum planes were accepted, the light is onscreen
4273 // otherwise we need to generate some more planes below...
4274 if (rtlight->cached_numfrustumplanes < 4)
4276 // at least one of the stock frustum planes failed, so we need to
4277 // create one or two custom planes to enclose the light origin
4278 for (i = 0;i < 4;i++)
4280 // create a plane using the view origin and light origin, and a
4281 // single point from the frustum corner set
4282 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
4283 VectorNormalize(plane.normal);
4284 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
4285 // see if this plane is backwards and flip it if so
4286 for (j = 0;j < 4;j++)
4287 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4291 VectorNegate(plane.normal, plane.normal);
4293 // flipped plane, test again to see if it is now valid
4294 for (j = 0;j < 4;j++)
4295 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4297 // if the plane is still not valid, then it is dividing the
4298 // frustum and has to be rejected
4302 // we have created a valid plane, compute extra info
4303 PlaneClassify(&plane);
4305 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4307 // if we've found 5 frustum planes then we have constructed a
4308 // proper split-side case and do not need to keep searching for
4309 // planes to enclose the light origin
4310 if (rtlight->cached_numfrustumplanes == 5)
4318 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
4320 plane = rtlight->cached_frustumplanes[i];
4321 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));
4326 // now add the light-space box planes if the light box is rotated, as any
4327 // caster outside the oriented light box is irrelevant (even if it passed
4328 // the worldspace light box, which is axial)
4329 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
4331 for (i = 0;i < 6;i++)
4335 v[i >> 1] = (i & 1) ? -1 : 1;
4336 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
4337 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
4338 plane.dist = VectorNormalizeLength(plane.normal);
4339 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
4340 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4346 // add the world-space reduced box planes
4347 for (i = 0;i < 6;i++)
4349 VectorClear(plane.normal);
4350 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
4351 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
4352 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4361 // reduce all plane distances to tightly fit the rtlight cull box, which
4363 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4364 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4365 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4366 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4367 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4368 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4369 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4370 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4371 oldnum = rtlight->cached_numfrustumplanes;
4372 rtlight->cached_numfrustumplanes = 0;
4373 for (j = 0;j < oldnum;j++)
4375 // find the nearest point on the box to this plane
4376 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
4377 for (i = 1;i < 8;i++)
4379 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
4380 if (bestdist > dist)
4383 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);
4384 // if the nearest point is near or behind the plane, we want this
4385 // plane, otherwise the plane is useless as it won't cull anything
4386 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
4388 PlaneClassify(&rtlight->cached_frustumplanes[j]);
4389 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
4396 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
4400 RSurf_ActiveWorldEntity();
4402 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4405 GL_CullFace(GL_NONE);
4406 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
4407 for (;mesh;mesh = mesh->next)
4409 if (!mesh->sidetotals[r_shadow_shadowmapside])
4411 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
4412 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4413 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);
4417 else if (r_refdef.scene.worldentity->model)
4418 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);
4420 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4423 static void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
4425 qboolean zpass = false;
4428 int surfacelistindex;
4429 msurface_t *surface;
4431 // if triangle neighbors are disabled, shadowvolumes are disabled
4432 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
4435 RSurf_ActiveWorldEntity();
4437 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4440 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
4442 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
4443 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
4445 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
4446 for (;mesh;mesh = mesh->next)
4448 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->numtriangles;
4449 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4450 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
4452 // increment stencil if frontface is infront of depthbuffer
4453 GL_CullFace(r_refdef.view.cullface_back);
4454 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
4455 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);
4456 // decrement stencil if backface is infront of depthbuffer
4457 GL_CullFace(r_refdef.view.cullface_front);
4458 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
4460 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
4462 // decrement stencil if backface is behind depthbuffer
4463 GL_CullFace(r_refdef.view.cullface_front);
4464 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
4465 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);
4466 // increment stencil if frontface is behind depthbuffer
4467 GL_CullFace(r_refdef.view.cullface_back);
4468 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
4470 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);
4474 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
4476 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
4477 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
4478 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
4480 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
4481 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
4482 if (CHECKPVSBIT(trispvs, t))
4483 shadowmarklist[numshadowmark++] = t;
4485 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);
4487 else if (numsurfaces)
4489 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);
4492 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4495 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
4497 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
4498 vec_t relativeshadowradius;
4499 RSurf_ActiveModelEntity(ent, false, false, false);
4500 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
4501 // we need to re-init the shader for each entity because the matrix changed
4502 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
4503 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
4504 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
4505 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
4506 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
4507 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
4508 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
4509 switch (r_shadow_rendermode)
4511 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
4512 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4515 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4518 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4521 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
4523 // set up properties for rendering light onto this entity
4524 RSurf_ActiveModelEntity(ent, true, true, false);
4525 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
4526 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4527 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4528 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4531 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
4533 if (!r_refdef.scene.worldmodel->DrawLight)
4536 // set up properties for rendering light onto this entity
4537 RSurf_ActiveWorldEntity();
4538 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
4539 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4540 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4541 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4543 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
4545 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4548 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
4550 dp_model_t *model = ent->model;
4551 if (!model->DrawLight)
4554 R_Shadow_SetupEntityLight(ent);
4556 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
4558 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4561 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
4565 int numleafs, numsurfaces;
4566 int *leaflist, *surfacelist;
4567 unsigned char *leafpvs;
4568 unsigned char *shadowtrispvs;
4569 unsigned char *lighttrispvs;
4570 //unsigned char *surfacesides;
4571 int numlightentities;
4572 int numlightentities_noselfshadow;
4573 int numshadowentities;
4574 int numshadowentities_noselfshadow;
4575 // FIXME: bounds check lightentities and shadowentities, etc.
4576 static entity_render_t *lightentities[MAX_EDICTS];
4577 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
4578 static entity_render_t *shadowentities[MAX_EDICTS];
4579 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
4581 qboolean castshadows;
4583 rtlight->draw = false;
4584 rtlight->cached_numlightentities = 0;
4585 rtlight->cached_numlightentities_noselfshadow = 0;
4586 rtlight->cached_numshadowentities = 0;
4587 rtlight->cached_numshadowentities_noselfshadow = 0;
4588 rtlight->cached_numsurfaces = 0;
4589 rtlight->cached_lightentities = NULL;
4590 rtlight->cached_lightentities_noselfshadow = NULL;
4591 rtlight->cached_shadowentities = NULL;
4592 rtlight->cached_shadowentities_noselfshadow = NULL;
4593 rtlight->cached_shadowtrispvs = NULL;
4594 rtlight->cached_lighttrispvs = NULL;
4595 rtlight->cached_surfacelist = NULL;
4596 rtlight->shadowmapsidesize = 0;
4598 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
4599 // skip lights that are basically invisible (color 0 0 0)
4600 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
4602 // loading is done before visibility checks because loading should happen
4603 // all at once at the start of a level, not when it stalls gameplay.
4604 // (especially important to benchmarks)
4606 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
4608 if (rtlight->compiled)
4609 R_RTLight_Uncompile(rtlight);
4610 R_RTLight_Compile(rtlight);
4614 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
4616 // look up the light style value at this time
4617 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4618 VectorScale(rtlight->color, f, rtlight->currentcolor);
4620 if (rtlight->selected)
4622 f = 2 + sin(realtime * M_PI * 4.0);
4623 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
4627 // if lightstyle is currently off, don't draw the light
4628 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
4631 // skip processing on corona-only lights
4635 // if the light box is offscreen, skip it
4636 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
4639 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
4640 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
4642 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4644 // 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
4645 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
4648 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
4650 // compiled light, world available and can receive realtime lighting
4651 // retrieve leaf information
4652 numleafs = rtlight->static_numleafs;
4653 leaflist = rtlight->static_leaflist;
4654 leafpvs = rtlight->static_leafpvs;
4655 numsurfaces = rtlight->static_numsurfaces;
4656 surfacelist = rtlight->static_surfacelist;
4657 //surfacesides = NULL;
4658 shadowtrispvs = rtlight->static_shadowtrispvs;
4659 lighttrispvs = rtlight->static_lighttrispvs;
4661 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4663 // dynamic light, world available and can receive realtime lighting
4664 // calculate lit surfaces and leafs
4665 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);
4666 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4667 leaflist = r_shadow_buffer_leaflist;
4668 leafpvs = r_shadow_buffer_leafpvs;
4669 surfacelist = r_shadow_buffer_surfacelist;
4670 //surfacesides = r_shadow_buffer_surfacesides;
4671 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4672 lighttrispvs = r_shadow_buffer_lighttrispvs;
4673 // if the reduced leaf bounds are offscreen, skip it
4674 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4685 //surfacesides = NULL;
4686 shadowtrispvs = NULL;
4687 lighttrispvs = NULL;
4689 // check if light is illuminating any visible leafs
4692 for (i = 0; i < numleafs; i++)
4693 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4699 // make a list of lit entities and shadow casting entities
4700 numlightentities = 0;
4701 numlightentities_noselfshadow = 0;
4702 numshadowentities = 0;
4703 numshadowentities_noselfshadow = 0;
4705 // add dynamic entities that are lit by the light
4706 for (i = 0; i < r_refdef.scene.numentities; i++)
4709 entity_render_t *ent = r_refdef.scene.entities[i];
4711 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4713 // skip the object entirely if it is not within the valid
4714 // shadow-casting region (which includes the lit region)
4715 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
4717 if (!(model = ent->model))
4719 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4721 // this entity wants to receive light, is visible, and is
4722 // inside the light box
4723 // TODO: check if the surfaces in the model can receive light
4724 // so now check if it's in a leaf seen by the light
4725 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))
4727 if (ent->flags & RENDER_NOSELFSHADOW)
4728 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
4730 lightentities[numlightentities++] = ent;
4731 // since it is lit, it probably also casts a shadow...
4732 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4733 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4734 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4736 // note: exterior models without the RENDER_NOSELFSHADOW
4737 // flag still create a RENDER_NOSELFSHADOW shadow but
4738 // are lit normally, this means that they are
4739 // self-shadowing but do not shadow other
4740 // RENDER_NOSELFSHADOW entities such as the gun
4741 // (very weird, but keeps the player shadow off the gun)
4742 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4743 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4745 shadowentities[numshadowentities++] = ent;
4748 else if (ent->flags & RENDER_SHADOW)
4750 // this entity is not receiving light, but may still need to
4752 // TODO: check if the surfaces in the model can cast shadow
4753 // now check if it is in a leaf seen by the light
4754 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))
4756 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4757 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4758 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4760 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4761 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4763 shadowentities[numshadowentities++] = ent;
4768 // return if there's nothing at all to light
4769 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4772 // count this light in the r_speeds
4773 r_refdef.stats[r_stat_lights]++;
4775 // flag it as worth drawing later
4776 rtlight->draw = true;
4778 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
4779 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4781 numshadowentities = numshadowentities_noselfshadow = 0;
4782 rtlight->castshadows = castshadows;
4784 // cache all the animated entities that cast a shadow but are not visible
4785 for (i = 0; i < numshadowentities; i++)
4786 R_AnimCache_GetEntity(shadowentities[i], false, false);
4787 for (i = 0; i < numshadowentities_noselfshadow; i++)
4788 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4790 // 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)
4791 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
4793 for (i = 0; i < numshadowentities_noselfshadow; i++)
4794 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
4795 numshadowentities_noselfshadow = 0;
4798 // we can convert noselfshadow to regular if there are no casters of that type
4799 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
4801 for (i = 0; i < numlightentities_noselfshadow; i++)
4802 lightentities[numlightentities++] = lightentities_noselfshadow[i];
4803 numlightentities_noselfshadow = 0;
4806 // allocate some temporary memory for rendering this light later in the frame
4807 // reusable buffers need to be copied, static data can be used as-is
4808 rtlight->cached_numlightentities = numlightentities;
4809 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
4810 rtlight->cached_numshadowentities = numshadowentities;
4811 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4812 rtlight->cached_numsurfaces = numsurfaces;
4813 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4814 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4815 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4816 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4817 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4819 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4820 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4821 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4822 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4823 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4827 // compiled light data
4828 rtlight->cached_shadowtrispvs = shadowtrispvs;
4829 rtlight->cached_lighttrispvs = lighttrispvs;
4830 rtlight->cached_surfacelist = surfacelist;
4833 if (R_Shadow_ShadowMappingEnabled())
4835 // figure out the shadowmapping parameters for this light
4836 vec3_t nearestpoint;
4839 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4840 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4841 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4842 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4843 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
4844 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4845 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4846 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4847 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
4851 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
4855 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4856 int numlightentities;
4857 int numlightentities_noselfshadow;
4858 int numshadowentities;
4859 int numshadowentities_noselfshadow;
4860 entity_render_t **lightentities;
4861 entity_render_t **lightentities_noselfshadow;
4862 entity_render_t **shadowentities;
4863 entity_render_t **shadowentities_noselfshadow;
4865 static unsigned char entitysides[MAX_EDICTS];
4866 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4872 matrix4x4_t radiustolight;
4874 // check if we cached this light this frame (meaning it is worth drawing)
4875 if (!rtlight->draw || !rtlight->castshadows)
4878 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
4879 if (rtlight->shadowmapatlassidesize == 0)
4881 rtlight->castshadows = false;
4885 // set up a scissor rectangle for this light
4886 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4889 // don't let sound skip if going slow
4890 if (r_refdef.scene.extraupdate)
4893 numlightentities = rtlight->cached_numlightentities;
4894 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4895 numshadowentities = rtlight->cached_numshadowentities;
4896 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4897 numsurfaces = rtlight->cached_numsurfaces;
4898 lightentities = rtlight->cached_lightentities;
4899 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4900 shadowentities = rtlight->cached_shadowentities;
4901 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4902 shadowtrispvs = rtlight->cached_shadowtrispvs;
4903 lighttrispvs = rtlight->cached_lighttrispvs;
4904 surfacelist = rtlight->cached_surfacelist;
4906 // make this the active rtlight for rendering purposes
4907 R_Shadow_RenderMode_ActiveLight(rtlight);
4909 radiustolight = rtlight->matrix_worldtolight;
4910 Matrix4x4_Abs(&radiustolight);
4912 size = rtlight->shadowmapatlassidesize;
4913 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4915 surfacesides = NULL;
4920 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4922 castermask = rtlight->static_shadowmap_casters;
4923 receivermask = rtlight->static_shadowmap_receivers;
4927 surfacesides = r_shadow_buffer_surfacesides;
4928 for (i = 0; i < numsurfaces; i++)
4930 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4931 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4932 castermask |= surfacesides[i];
4933 receivermask |= surfacesides[i];
4938 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
4939 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4940 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
4941 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4943 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4947 for (i = 0; i < numshadowentities; i++)
4948 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4949 for (i = 0; i < numshadowentities_noselfshadow; i++)
4950 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4953 // there is no need to render shadows for sides that have no receivers...
4954 castermask &= receivermask;
4956 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
4958 // render shadow casters into shadowmaps for this light
4959 for (side = 0; side < 6; side++)
4961 int bit = 1 << side;
4962 if (castermask & bit)
4964 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
4966 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4967 for (i = 0; i < numshadowentities; i++)
4968 if (entitysides[i] & bit)
4969 R_Shadow_DrawEntityShadow(shadowentities[i]);
4970 for (i = 0; i < numshadowentities_noselfshadow; i++)
4971 if (entitysides_noselfshadow[i] & bit)
4972 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4975 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
4976 if (numshadowentities_noselfshadow)
4978 for (side = 0; side < 6; side++)
4980 int bit = 1 << side;
4981 if (castermask & bit)
4983 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
4985 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4986 for (i = 0; i < numshadowentities; i++)
4987 if (entitysides[i] & bit)
4988 R_Shadow_DrawEntityShadow(shadowentities[i]);
4994 static void R_Shadow_DrawLight(rtlight_t *rtlight)
4998 unsigned char *shadowtrispvs, *lighttrispvs;
4999 int numlightentities;
5000 int numlightentities_noselfshadow;
5001 int numshadowentities;
5002 int numshadowentities_noselfshadow;
5003 entity_render_t **lightentities;
5004 entity_render_t **lightentities_noselfshadow;
5005 entity_render_t **shadowentities;
5006 entity_render_t **shadowentities_noselfshadow;
5008 qboolean castshadows;
5010 // check if we cached this light this frame (meaning it is worth drawing)
5014 // set up a scissor rectangle for this light
5015 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
5018 // don't let sound skip if going slow
5019 if (r_refdef.scene.extraupdate)
5022 numlightentities = rtlight->cached_numlightentities;
5023 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
5024 numshadowentities = rtlight->cached_numshadowentities;
5025 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
5026 numsurfaces = rtlight->cached_numsurfaces;
5027 lightentities = rtlight->cached_lightentities;
5028 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
5029 shadowentities = rtlight->cached_shadowentities;
5030 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
5031 shadowtrispvs = rtlight->cached_shadowtrispvs;
5032 lighttrispvs = rtlight->cached_lighttrispvs;
5033 surfacelist = rtlight->cached_surfacelist;
5034 castshadows = rtlight->castshadows;
5036 // make this the active rtlight for rendering purposes
5037 R_Shadow_RenderMode_ActiveLight(rtlight);
5039 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
5041 // optionally draw visible shape of the shadow volumes
5042 // for performance analysis by level designers
5043 R_Shadow_RenderMode_VisibleShadowVolumes();
5045 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
5046 for (i = 0;i < numshadowentities;i++)
5047 R_Shadow_DrawEntityShadow(shadowentities[i]);
5048 for (i = 0;i < numshadowentities_noselfshadow;i++)
5049 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5050 R_Shadow_RenderMode_VisibleLighting(false, false);
5053 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
5055 // optionally draw the illuminated areas
5056 // for performance analysis by level designers
5057 R_Shadow_RenderMode_VisibleLighting(false, false);
5059 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5060 for (i = 0;i < numlightentities;i++)
5061 R_Shadow_DrawEntityLight(lightentities[i]);
5062 for (i = 0;i < numlightentities_noselfshadow;i++)
5063 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5066 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
5070 float shadowmapoffsetnoselfshadow = 0;
5071 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
5072 Matrix4x4_Abs(&radiustolight);
5074 size = rtlight->shadowmapatlassidesize;
5075 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
5077 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
5079 if (rtlight->cached_numshadowentities_noselfshadow)
5080 shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
5082 // render lighting using the depth texture as shadowmap
5083 // draw lighting in the unmasked areas
5084 if (numsurfaces + numlightentities)
5086 R_Shadow_RenderMode_Lighting(false, false, true, false);
5087 // draw lighting in the unmasked areas
5089 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5090 for (i = 0; i < numlightentities; i++)
5091 R_Shadow_DrawEntityLight(lightentities[i]);
5093 // offset to the noselfshadow part of the atlas and draw those too
5094 if (numlightentities_noselfshadow)
5096 R_Shadow_RenderMode_Lighting(false, false, true, true);
5097 for (i = 0; i < numlightentities_noselfshadow; i++)
5098 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5101 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5102 if (r_shadow_usingdeferredprepass)
5103 R_Shadow_RenderMode_DrawDeferredLight(true);
5105 else if (castshadows && vid.stencil)
5107 // draw stencil shadow volumes to mask off pixels that are in shadow
5108 // so that they won't receive lighting
5109 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
5110 R_Shadow_ClearStencil();
5113 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
5114 for (i = 0;i < numshadowentities;i++)
5115 R_Shadow_DrawEntityShadow(shadowentities[i]);
5117 // draw lighting in the unmasked areas
5118 R_Shadow_RenderMode_Lighting(true, false, false, false);
5119 for (i = 0;i < numlightentities_noselfshadow;i++)
5120 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5122 for (i = 0;i < numshadowentities_noselfshadow;i++)
5123 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5125 // draw lighting in the unmasked areas
5126 R_Shadow_RenderMode_Lighting(true, false, false, false);
5128 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5129 for (i = 0;i < numlightentities;i++)
5130 R_Shadow_DrawEntityLight(lightentities[i]);
5132 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5133 if (r_shadow_usingdeferredprepass)
5134 R_Shadow_RenderMode_DrawDeferredLight(false);
5138 // draw lighting in the unmasked areas
5139 R_Shadow_RenderMode_Lighting(false, false, false, false);
5141 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5142 for (i = 0;i < numlightentities;i++)
5143 R_Shadow_DrawEntityLight(lightentities[i]);
5144 for (i = 0;i < numlightentities_noselfshadow;i++)
5145 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5147 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5148 if (r_shadow_usingdeferredprepass)
5149 R_Shadow_RenderMode_DrawDeferredLight(false);
5153 static void R_Shadow_FreeDeferred(void)
5155 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
5156 r_shadow_prepassgeometryfbo = 0;
5158 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
5159 r_shadow_prepasslightingdiffusespecularfbo = 0;
5161 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
5162 r_shadow_prepasslightingdiffusefbo = 0;
5164 if (r_shadow_prepassgeometrydepthbuffer)
5165 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
5166 r_shadow_prepassgeometrydepthbuffer = NULL;
5168 if (r_shadow_prepassgeometrynormalmaptexture)
5169 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
5170 r_shadow_prepassgeometrynormalmaptexture = NULL;
5172 if (r_shadow_prepasslightingdiffusetexture)
5173 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
5174 r_shadow_prepasslightingdiffusetexture = NULL;
5176 if (r_shadow_prepasslightingspeculartexture)
5177 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
5178 r_shadow_prepasslightingspeculartexture = NULL;
5181 void R_Shadow_DrawPrepass(void)
5185 entity_render_t *ent;
5186 float clearcolor[4];
5188 R_Mesh_ResetTextureState();
5190 GL_ColorMask(1,1,1,1);
5191 GL_BlendFunc(GL_ONE, GL_ZERO);
5194 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5195 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
5196 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
5197 if (r_timereport_active)
5198 R_TimeReport("prepasscleargeom");
5200 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
5201 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
5202 if (r_timereport_active)
5203 R_TimeReport("prepassworld");
5205 for (i = 0;i < r_refdef.scene.numentities;i++)
5207 if (!r_refdef.viewcache.entityvisible[i])
5209 ent = r_refdef.scene.entities[i];
5210 if (ent->model && ent->model->DrawPrepass != NULL)
5211 ent->model->DrawPrepass(ent);
5214 if (r_timereport_active)
5215 R_TimeReport("prepassmodels");
5217 GL_DepthMask(false);
5218 GL_ColorMask(1,1,1,1);
5221 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5222 Vector4Set(clearcolor, 0, 0, 0, 0);
5223 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
5224 if (r_timereport_active)
5225 R_TimeReport("prepassclearlit");
5227 R_Shadow_RenderMode_Begin();
5229 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5230 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5232 R_Shadow_RenderMode_End();
5234 if (r_timereport_active)
5235 R_TimeReport("prepasslights");
5238 #define MAX_SCENELIGHTS 65536
5239 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
5241 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
5243 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
5245 r_shadow_scenemaxlights *= 2;
5246 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
5247 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
5249 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
5253 void R_Shadow_DrawLightSprites(void);
5254 void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
5263 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
5264 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
5265 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
5267 if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
5268 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
5269 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
5270 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
5271 r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) ||
5272 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
5273 r_shadow_shadowmapborder != shadowmapborder ||
5274 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
5275 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
5276 R_Shadow_FreeShadowMaps();
5278 r_shadow_fb_fbo = fbo;
5279 r_shadow_fb_depthtexture = depthtexture;
5280 r_shadow_fb_colortexture = colortexture;
5282 r_shadow_usingshadowmaportho = false;
5284 switch (vid.renderpath)
5286 case RENDERPATH_GL20:
5287 case RENDERPATH_D3D9:
5288 case RENDERPATH_D3D10:
5289 case RENDERPATH_D3D11:
5290 case RENDERPATH_SOFT:
5292 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
5294 r_shadow_usingdeferredprepass = false;
5295 if (r_shadow_prepass_width)
5296 R_Shadow_FreeDeferred();
5297 r_shadow_prepass_width = r_shadow_prepass_height = 0;
5301 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
5303 R_Shadow_FreeDeferred();
5305 r_shadow_usingdeferredprepass = true;
5306 r_shadow_prepass_width = vid.width;
5307 r_shadow_prepass_height = vid.height;
5308 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
5309 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);
5310 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);
5311 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);
5313 // set up the geometry pass fbo (depth + normalmap)
5314 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5315 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5316 // render depth into a renderbuffer and other important properties into the normalmap texture
5318 // set up the lighting pass fbo (diffuse + specular)
5319 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5320 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5321 // render diffuse into one texture and specular into another,
5322 // with depth and normalmap bound as textures,
5323 // with depth bound as attachment as well
5325 // set up the lighting pass fbo (diffuse)
5326 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5327 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5328 // render diffuse into one texture,
5329 // with depth and normalmap bound as textures,
5330 // with depth bound as attachment as well
5334 case RENDERPATH_GL11:
5335 case RENDERPATH_GL13:
5336 case RENDERPATH_GLES1:
5337 case RENDERPATH_GLES2:
5338 r_shadow_usingdeferredprepass = false;
5342 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);
5344 r_shadow_scenenumlights = 0;
5345 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5346 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5347 for (lightindex = 0; lightindex < range; lightindex++)
5349 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5350 if (light && (light->flags & flag))
5352 R_Shadow_PrepareLight(&light->rtlight);
5353 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5356 if (r_refdef.scene.rtdlight)
5358 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5360 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
5361 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
5364 else if (gl_flashblend.integer)
5366 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5368 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
5369 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
5370 VectorScale(rtlight->color, f, rtlight->currentcolor);
5374 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
5375 if (r_shadow_debuglight.integer >= 0)
5377 r_shadow_scenenumlights = 0;
5378 lightindex = r_shadow_debuglight.integer;
5379 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5382 R_Shadow_PrepareLight(&light->rtlight);
5383 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5387 // if we're doing shadowmaps we need to prepare the atlas layout now
5388 if (R_Shadow_ShadowMappingEnabled())
5392 // allocate shadowmaps in the atlas now
5393 // 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...
5394 for (lod = 0; lod < 16; lod++)
5396 int packing_success = 0;
5397 int packing_failure = 0;
5398 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
5399 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
5400 if (r_shadow_shadowmapatlas_modelshadows_size)
5401 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);
5402 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5404 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
5405 int size = rtlight->shadowmapsidesize >> lod;
5407 if (!rtlight->castshadows)
5409 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
5412 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
5413 if (rtlight->cached_numshadowentities_noselfshadow)
5415 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
5417 rtlight->shadowmapatlassidesize = size;
5422 // note down that we failed to pack this one, it will have to disable shadows
5423 rtlight->shadowmapatlassidesize = 0;
5427 // generally everything fits and we stop here on the first iteration
5428 if (packing_failure == 0)
5433 if (r_editlights.integer)
5434 R_Shadow_DrawLightSprites();
5437 void R_Shadow_DrawShadowMaps(void)
5439 R_Shadow_RenderMode_Begin();
5440 R_Shadow_RenderMode_ActiveLight(NULL);
5442 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
5443 R_Shadow_ClearShadowMapTexture();
5445 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
5446 if (r_shadow_shadowmapatlas_modelshadows_size)
5448 R_Shadow_DrawModelShadowMaps();
5449 // don't let sound skip if going slow
5450 if (r_refdef.scene.extraupdate)
5454 if (R_Shadow_ShadowMappingEnabled())
5457 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5458 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
5461 R_Shadow_RenderMode_End();
5464 void R_Shadow_DrawLights(void)
5468 R_Shadow_RenderMode_Begin();
5470 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5471 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5473 R_Shadow_RenderMode_End();
5476 #define MAX_MODELSHADOWS 1024
5477 static int r_shadow_nummodelshadows;
5478 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
5480 void R_Shadow_PrepareModelShadows(void)
5483 float scale, size, radius, dot1, dot2;
5484 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5485 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
5486 entity_render_t *ent;
5488 r_shadow_nummodelshadows = 0;
5489 r_shadow_shadowmapatlas_modelshadows_size = 0;
5491 if (!r_refdef.scene.numentities || r_refdef.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
5494 switch (r_shadow_shadowmode)
5496 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
5497 if (r_shadows.integer >= 2)
5500 case R_SHADOW_SHADOWMODE_STENCIL:
5503 for (i = 0; i < r_refdef.scene.numentities; i++)
5505 ent = r_refdef.scene.entities[i];
5506 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5508 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5510 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5511 R_AnimCache_GetEntity(ent, false, false);
5519 size = 2 * r_shadow_shadowmapmaxsize;
5520 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
5521 radius = 0.5f * size / scale;
5523 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5524 VectorCopy(prvmshadowdir, shadowdir);
5525 VectorNormalize(shadowdir);
5526 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5527 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5528 if (fabs(dot1) <= fabs(dot2))
5529 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5531 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5532 VectorNormalize(shadowforward);
5533 CrossProduct(shadowdir, shadowforward, shadowright);
5534 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5535 VectorCopy(prvmshadowfocus, shadowfocus);
5536 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5537 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5538 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5539 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5540 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5542 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5544 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5545 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5546 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5547 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5548 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5549 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5551 for (i = 0; i < r_refdef.scene.numentities; i++)
5553 ent = r_refdef.scene.entities[i];
5554 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
5556 // cast shadows from anything of the map (submodels are optional)
5557 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5559 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5561 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5562 R_AnimCache_GetEntity(ent, false, false);
5566 if (r_shadow_nummodelshadows)
5568 r_shadow_shadowmapatlas_modelshadows_x = 0;
5569 r_shadow_shadowmapatlas_modelshadows_y = 0;
5570 r_shadow_shadowmapatlas_modelshadows_size = size;
5574 static void R_Shadow_DrawModelShadowMaps(void)
5577 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
5578 entity_render_t *ent;
5579 vec3_t relativelightorigin;
5580 vec3_t relativelightdirection, relativeforward, relativeright;
5581 vec3_t relativeshadowmins, relativeshadowmaxs;
5582 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
5583 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5585 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
5586 r_viewport_t viewport;
5588 size = r_shadow_shadowmapatlas_modelshadows_size;
5589 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
5590 radius = 0.5f / scale;
5591 nearclip = -r_shadows_throwdistance.value;
5592 farclip = r_shadows_throwdistance.value;
5593 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);
5595 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
5596 r_shadow_modelshadowmap_parameters[0] = size;
5597 r_shadow_modelshadowmap_parameters[1] = size;
5598 r_shadow_modelshadowmap_parameters[2] = 1.0;
5599 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
5600 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
5601 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
5602 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
5603 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
5604 r_shadow_usingshadowmaportho = true;
5606 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5607 VectorCopy(prvmshadowdir, shadowdir);
5608 VectorNormalize(shadowdir);
5609 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5610 VectorCopy(prvmshadowfocus, shadowfocus);
5611 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5612 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5613 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5614 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5615 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5616 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5617 if (fabs(dot1) <= fabs(dot2))
5618 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5620 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5621 VectorNormalize(shadowforward);
5622 VectorM(scale, shadowforward, &m[0]);
5623 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5625 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
5626 CrossProduct(shadowdir, shadowforward, shadowright);
5627 VectorM(scale, shadowright, &m[4]);
5628 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
5629 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
5630 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
5631 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
5632 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
5633 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);
5634 R_SetViewport(&viewport);
5636 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5638 // render into a slightly restricted region so that the borders of the
5639 // shadowmap area fade away, rather than streaking across everything
5640 // outside the usable area
5641 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
5643 for (i = 0;i < r_shadow_nummodelshadows;i++)
5645 ent = r_shadow_modelshadows[i];
5646 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5647 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
5648 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5649 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
5650 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
5651 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5652 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5653 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5654 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5655 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5656 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5657 RSurf_ActiveModelEntity(ent, false, false, false);
5658 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
5659 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5665 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
5667 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
5669 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
5670 Cvar_SetValueQuick(&r_test, 0);
5675 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
5676 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
5677 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
5678 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
5679 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
5680 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
5682 switch (vid.renderpath)
5684 case RENDERPATH_GL11:
5685 case RENDERPATH_GL13:
5686 case RENDERPATH_GL20:
5687 case RENDERPATH_SOFT:
5688 case RENDERPATH_GLES1:
5689 case RENDERPATH_GLES2:
5691 case RENDERPATH_D3D9:
5692 case RENDERPATH_D3D10:
5693 case RENDERPATH_D3D11:
5694 #ifdef MATRIX4x4_OPENGLORIENTATION
5695 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5696 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
5697 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
5698 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
5700 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5701 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
5702 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
5703 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
5709 void R_Shadow_DrawModelShadows(void)
5712 float relativethrowdistance;
5713 entity_render_t *ent;
5714 vec3_t relativelightorigin;
5715 vec3_t relativelightdirection;
5716 vec3_t relativeshadowmins, relativeshadowmaxs;
5717 vec3_t tmp, shadowdir;
5718 prvm_vec3_t prvmshadowdir;
5720 if (!r_shadow_nummodelshadows || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
5723 R_ResetViewRendering3D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5724 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
5725 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5726 R_Shadow_RenderMode_Begin();
5727 R_Shadow_RenderMode_ActiveLight(NULL);
5728 r_shadow_lightscissor[0] = r_refdef.view.x;
5729 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
5730 r_shadow_lightscissor[2] = r_refdef.view.width;
5731 r_shadow_lightscissor[3] = r_refdef.view.height;
5732 R_Shadow_RenderMode_StencilShadowVolumes(false);
5735 if (r_shadows.integer == 2)
5737 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5738 VectorCopy(prvmshadowdir, shadowdir);
5739 VectorNormalize(shadowdir);
5742 R_Shadow_ClearStencil();
5744 for (i = 0;i < r_shadow_nummodelshadows;i++)
5746 ent = r_shadow_modelshadows[i];
5748 // cast shadows from anything of the map (submodels are optional)
5749 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5750 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
5751 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
5752 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
5753 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5756 if(ent->entitynumber != 0)
5758 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
5760 // FIXME handle this
5761 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5765 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
5766 int entnum, entnum2, recursion;
5767 entnum = entnum2 = ent->entitynumber;
5768 for(recursion = 32; recursion > 0; --recursion)
5770 entnum2 = cl.entities[entnum].state_current.tagentity;
5771 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
5776 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
5778 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
5779 // transform into modelspace of OUR entity
5780 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
5781 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
5784 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5788 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5791 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
5792 RSurf_ActiveModelEntity(ent, false, false, false);
5793 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
5794 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5797 // not really the right mode, but this will disable any silly stencil features
5798 R_Shadow_RenderMode_End();
5800 // set up ortho view for rendering this pass
5801 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5802 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5803 //GL_ScissorTest(true);
5804 //R_EntityMatrix(&identitymatrix);
5805 //R_Mesh_ResetTextureState();
5806 R_ResetViewRendering2D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5808 // set up a darkening blend on shadowed areas
5809 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5810 //GL_DepthRange(0, 1);
5811 //GL_DepthTest(false);
5812 //GL_DepthMask(false);
5813 //GL_PolygonOffset(0, 0);CHECKGLERROR
5814 GL_Color(0, 0, 0, r_shadows_darken.value);
5815 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5816 //GL_DepthFunc(GL_ALWAYS);
5817 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5819 // apply the blend to the shadowed areas
5820 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5821 R_SetupShader_Generic_NoTexture(false, true);
5822 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5824 // restore the viewport
5825 R_SetViewport(&r_refdef.view.viewport);
5827 // restore other state to normal
5828 //R_Shadow_RenderMode_End();
5831 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5834 vec3_t centerorigin;
5835 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5838 // if it's too close, skip it
5839 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5841 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5844 if (usequery && r_numqueries + 2 <= r_maxqueries)
5846 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5847 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5848 // 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
5849 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5851 switch(vid.renderpath)
5853 case RENDERPATH_GL11:
5854 case RENDERPATH_GL13:
5855 case RENDERPATH_GL20:
5856 case RENDERPATH_GLES1:
5857 case RENDERPATH_GLES2:
5858 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5860 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5861 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5862 GL_DepthFunc(GL_ALWAYS);
5863 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5864 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5865 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5866 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5867 GL_DepthFunc(GL_LEQUAL);
5868 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5869 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5870 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5871 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5872 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5876 case RENDERPATH_D3D9:
5877 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5879 case RENDERPATH_D3D10:
5880 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5882 case RENDERPATH_D3D11:
5883 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5885 case RENDERPATH_SOFT:
5886 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5890 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5893 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5895 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5898 unsigned int occlude = 0;
5899 GLint allpixels = 0, visiblepixels = 0;
5901 // now we have to check the query result
5902 if (rtlight->corona_queryindex_visiblepixels)
5904 switch(vid.renderpath)
5906 case RENDERPATH_GL11:
5907 case RENDERPATH_GL13:
5908 case RENDERPATH_GL20:
5909 case RENDERPATH_GLES1:
5910 case RENDERPATH_GLES2:
5911 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5913 // See if we can use the GPU-side method to prevent implicit sync
5914 if (vid.support.arb_query_buffer_object) {
5915 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
5916 if (!r_shadow_occlusion_buf) {
5917 qglGenBuffersARB(1, &r_shadow_occlusion_buf);
5918 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5919 qglBufferDataARB(GL_QUERY_BUFFER_ARB, 8, NULL, GL_DYNAMIC_COPY);
5921 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5923 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(0));
5924 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4));
5925 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
5926 occlude = MATERIALFLAG_OCCLUDE;
5928 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5929 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5930 if (visiblepixels < 1 || allpixels < 1)
5932 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5934 cscale *= rtlight->corona_visibility;
5940 case RENDERPATH_D3D9:
5941 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5943 case RENDERPATH_D3D10:
5944 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5946 case RENDERPATH_D3D11:
5947 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5949 case RENDERPATH_SOFT:
5950 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5958 // FIXME: these traces should scan all render entities instead of cl.world
5959 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)
5962 VectorScale(rtlight->currentcolor, cscale, color);
5963 if (VectorLength(color) > (1.0f / 256.0f))
5966 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
5969 VectorNegate(color, color);
5970 GL_BlendEquationSubtract(true);
5972 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5973 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);
5974 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
5976 GL_BlendEquationSubtract(false);
5980 void R_Shadow_DrawCoronas(void)
5983 qboolean usequery = false;
5988 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
5990 if (r_fb.water.renderingscene)
5992 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5993 R_EntityMatrix(&identitymatrix);
5995 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5997 // check occlusion of coronas
5998 // use GL_ARB_occlusion_query if available
5999 // otherwise use raytraces
6001 switch (vid.renderpath)
6003 case RENDERPATH_GL11:
6004 case RENDERPATH_GL13:
6005 case RENDERPATH_GL20:
6006 case RENDERPATH_GLES1:
6007 case RENDERPATH_GLES2:
6008 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
6009 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
6012 GL_ColorMask(0,0,0,0);
6013 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
6014 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
6017 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
6018 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
6020 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
6023 RSurf_ActiveWorldEntity();
6024 GL_BlendFunc(GL_ONE, GL_ZERO);
6025 GL_CullFace(GL_NONE);
6026 GL_DepthMask(false);
6027 GL_DepthRange(0, 1);
6028 GL_PolygonOffset(0, 0);
6030 R_Mesh_ResetTextureState();
6031 R_SetupShader_Generic_NoTexture(false, false);
6035 case RENDERPATH_D3D9:
6037 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6039 case RENDERPATH_D3D10:
6040 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6042 case RENDERPATH_D3D11:
6043 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6045 case RENDERPATH_SOFT:
6047 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6050 for (lightindex = 0;lightindex < range;lightindex++)
6052 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6055 rtlight = &light->rtlight;
6056 rtlight->corona_visibility = 0;
6057 rtlight->corona_queryindex_visiblepixels = 0;
6058 rtlight->corona_queryindex_allpixels = 0;
6059 if (!(rtlight->flags & flag))
6061 if (rtlight->corona <= 0)
6063 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
6065 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6067 for (i = 0;i < r_refdef.scene.numlights;i++)
6069 rtlight = r_refdef.scene.lights[i];
6070 rtlight->corona_visibility = 0;
6071 rtlight->corona_queryindex_visiblepixels = 0;
6072 rtlight->corona_queryindex_allpixels = 0;
6073 if (!(rtlight->flags & flag))
6075 if (rtlight->corona <= 0)
6077 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6080 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
6082 // now draw the coronas using the query data for intensity info
6083 for (lightindex = 0;lightindex < range;lightindex++)
6085 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6088 rtlight = &light->rtlight;
6089 if (rtlight->corona_visibility <= 0)
6091 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6093 for (i = 0;i < r_refdef.scene.numlights;i++)
6095 rtlight = r_refdef.scene.lights[i];
6096 if (rtlight->corona_visibility <= 0)
6098 if (gl_flashblend.integer)
6099 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
6101 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6107 static dlight_t *R_Shadow_NewWorldLight(void)
6109 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
6112 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)
6116 // 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
6118 // validate parameters
6122 // copy to light properties
6123 VectorCopy(origin, light->origin);
6124 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
6125 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
6126 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
6128 light->color[0] = max(color[0], 0);
6129 light->color[1] = max(color[1], 0);
6130 light->color[2] = max(color[2], 0);
6132 light->color[0] = color[0];
6133 light->color[1] = color[1];
6134 light->color[2] = color[2];
6135 light->radius = max(radius, 0);
6136 light->style = style;
6137 light->shadow = shadowenable;
6138 light->corona = corona;
6139 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
6140 light->coronasizescale = coronasizescale;
6141 light->ambientscale = ambientscale;
6142 light->diffusescale = diffusescale;
6143 light->specularscale = specularscale;
6144 light->flags = flags;
6146 // update renderable light data
6147 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
6148 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);
6151 static void R_Shadow_FreeWorldLight(dlight_t *light)
6153 if (r_shadow_selectedlight == light)
6154 r_shadow_selectedlight = NULL;
6155 R_RTLight_Uncompile(&light->rtlight);
6156 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
6159 void R_Shadow_ClearWorldLights(void)
6163 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6164 for (lightindex = 0;lightindex < range;lightindex++)
6166 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6168 R_Shadow_FreeWorldLight(light);
6170 r_shadow_selectedlight = NULL;
6173 static void R_Shadow_SelectLight(dlight_t *light)
6175 if (r_shadow_selectedlight)
6176 r_shadow_selectedlight->selected = false;
6177 r_shadow_selectedlight = light;
6178 if (r_shadow_selectedlight)
6179 r_shadow_selectedlight->selected = true;
6182 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6184 // this is never batched (there can be only one)
6186 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
6187 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6188 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6191 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6196 skinframe_t *skinframe;
6199 // this is never batched (due to the ent parameter changing every time)
6200 // so numsurfaces == 1 and surfacelist[0] == lightnumber
6201 const dlight_t *light = (dlight_t *)ent;
6204 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
6207 VectorScale(light->color, intensity, spritecolor);
6208 if (VectorLength(spritecolor) < 0.1732f)
6209 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
6210 if (VectorLength(spritecolor) > 1.0f)
6211 VectorNormalize(spritecolor);
6213 // draw light sprite
6214 if (light->cubemapname[0] && !light->shadow)
6215 skinframe = r_editlights_sprcubemapnoshadowlight;
6216 else if (light->cubemapname[0])
6217 skinframe = r_editlights_sprcubemaplight;
6218 else if (!light->shadow)
6219 skinframe = r_editlights_sprnoshadowlight;
6221 skinframe = r_editlights_sprlight;
6223 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);
6224 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6226 // draw selection sprite if light is selected
6227 if (light->selected)
6229 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6230 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6231 // VorteX todo: add normalmode/realtime mode light overlay sprites?
6235 void R_Shadow_DrawLightSprites(void)
6239 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6240 for (lightindex = 0;lightindex < range;lightindex++)
6242 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6244 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
6246 if (!r_editlights_lockcursor)
6247 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
6250 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
6255 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6256 if (lightindex >= range)
6258 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6261 rtlight = &light->rtlight;
6262 //if (!(rtlight->flags & flag))
6264 VectorCopy(rtlight->shadoworigin, origin);
6265 *radius = rtlight->radius;
6266 VectorCopy(rtlight->color, color);
6270 static void R_Shadow_SelectLightInView(void)
6272 float bestrating, rating, temp[3];
6276 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6280 if (r_editlights_lockcursor)
6282 for (lightindex = 0;lightindex < range;lightindex++)
6284 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6287 VectorSubtract(light->origin, r_refdef.view.origin, temp);
6288 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
6291 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
6292 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)
6294 bestrating = rating;
6299 R_Shadow_SelectLight(best);
6302 void R_Shadow_LoadWorldLights(void)
6304 int n, a, style, shadow, flags;
6305 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
6306 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
6307 if (cl.worldmodel == NULL)
6309 Con_Print("No map loaded.\n");
6312 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6313 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6323 for (;COM_Parse(t, true) && strcmp(
6324 if (COM_Parse(t, true))
6326 if (com_token[0] == '!')
6329 origin[0] = atof(com_token+1);
6332 origin[0] = atof(com_token);
6337 while (*s && *s != '\n' && *s != '\r')
6343 // check for modifier flags
6350 #if _MSC_VER >= 1400
6351 #define sscanf sscanf_s
6353 cubemapname[sizeof(cubemapname)-1] = 0;
6354 #if MAX_QPATH != 128
6355 #error update this code if MAX_QPATH changes
6357 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
6358 #if _MSC_VER >= 1400
6359 , sizeof(cubemapname)
6361 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
6364 flags = LIGHTFLAG_REALTIMEMODE;
6372 coronasizescale = 0.25f;
6374 VectorClear(angles);
6377 if (a < 9 || !strcmp(cubemapname, "\"\""))
6379 // remove quotes on cubemapname
6380 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
6383 namelen = strlen(cubemapname) - 2;
6384 memmove(cubemapname, cubemapname + 1, namelen);
6385 cubemapname[namelen] = '\0';
6389 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);
6392 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6400 Con_Printf("invalid rtlights file \"%s\"\n", name);
6401 Mem_Free(lightsstring);
6405 void R_Shadow_SaveWorldLights(void)
6409 size_t bufchars, bufmaxchars;
6411 char name[MAX_QPATH];
6412 char line[MAX_INPUTLINE];
6413 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
6414 // I hate lines which are 3 times my screen size :( --blub
6417 if (cl.worldmodel == NULL)
6419 Con_Print("No map loaded.\n");
6422 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6423 bufchars = bufmaxchars = 0;
6425 for (lightindex = 0;lightindex < range;lightindex++)
6427 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6430 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
6431 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);
6432 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
6433 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]);
6435 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);
6436 if (bufchars + strlen(line) > bufmaxchars)
6438 bufmaxchars = bufchars + strlen(line) + 2048;
6440 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
6444 memcpy(buf, oldbuf, bufchars);
6450 memcpy(buf + bufchars, line, strlen(line));
6451 bufchars += strlen(line);
6455 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
6460 void R_Shadow_LoadLightsFile(void)
6463 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
6464 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
6465 if (cl.worldmodel == NULL)
6467 Con_Print("No map loaded.\n");
6470 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
6471 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6479 while (*s && *s != '\n' && *s != '\r')
6485 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);
6489 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);
6492 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
6493 radius = bound(15, radius, 4096);
6494 VectorScale(color, (2.0f / (8388608.0f)), color);
6495 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6503 Con_Printf("invalid lights file \"%s\"\n", name);
6504 Mem_Free(lightsstring);
6508 // tyrlite/hmap2 light types in the delay field
6509 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
6511 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
6523 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
6524 char key[256], value[MAX_INPUTLINE];
6527 if (cl.worldmodel == NULL)
6529 Con_Print("No map loaded.\n");
6532 // try to load a .ent file first
6533 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
6534 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
6535 // and if that is not found, fall back to the bsp file entity string
6537 data = cl.worldmodel->brush.entities;
6540 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
6542 type = LIGHTTYPE_MINUSX;
6543 origin[0] = origin[1] = origin[2] = 0;
6544 originhack[0] = originhack[1] = originhack[2] = 0;
6545 angles[0] = angles[1] = angles[2] = 0;
6546 color[0] = color[1] = color[2] = 1;
6547 light[0] = light[1] = light[2] = 1;light[3] = 300;
6548 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
6558 if (!COM_ParseToken_Simple(&data, false, false, true))
6560 if (com_token[0] == '}')
6561 break; // end of entity
6562 if (com_token[0] == '_')
6563 strlcpy(key, com_token + 1, sizeof(key));
6565 strlcpy(key, com_token, sizeof(key));
6566 while (key[strlen(key)-1] == ' ') // remove trailing spaces
6567 key[strlen(key)-1] = 0;
6568 if (!COM_ParseToken_Simple(&data, false, false, true))
6570 strlcpy(value, com_token, sizeof(value));
6572 // now that we have the key pair worked out...
6573 if (!strcmp("light", key))
6575 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
6579 light[0] = vec[0] * (1.0f / 256.0f);
6580 light[1] = vec[0] * (1.0f / 256.0f);
6581 light[2] = vec[0] * (1.0f / 256.0f);
6587 light[0] = vec[0] * (1.0f / 255.0f);
6588 light[1] = vec[1] * (1.0f / 255.0f);
6589 light[2] = vec[2] * (1.0f / 255.0f);
6593 else if (!strcmp("delay", key))
6595 else if (!strcmp("origin", key))
6596 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
6597 else if (!strcmp("angle", key))
6598 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
6599 else if (!strcmp("angles", key))
6600 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
6601 else if (!strcmp("color", key))
6602 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
6603 else if (!strcmp("wait", key))
6604 fadescale = atof(value);
6605 else if (!strcmp("classname", key))
6607 if (!strncmp(value, "light", 5))
6610 if (!strcmp(value, "light_fluoro"))
6615 overridecolor[0] = 1;
6616 overridecolor[1] = 1;
6617 overridecolor[2] = 1;
6619 if (!strcmp(value, "light_fluorospark"))
6624 overridecolor[0] = 1;
6625 overridecolor[1] = 1;
6626 overridecolor[2] = 1;
6628 if (!strcmp(value, "light_globe"))
6633 overridecolor[0] = 1;
6634 overridecolor[1] = 0.8;
6635 overridecolor[2] = 0.4;
6637 if (!strcmp(value, "light_flame_large_yellow"))
6642 overridecolor[0] = 1;
6643 overridecolor[1] = 0.5;
6644 overridecolor[2] = 0.1;
6646 if (!strcmp(value, "light_flame_small_yellow"))
6651 overridecolor[0] = 1;
6652 overridecolor[1] = 0.5;
6653 overridecolor[2] = 0.1;
6655 if (!strcmp(value, "light_torch_small_white"))
6660 overridecolor[0] = 1;
6661 overridecolor[1] = 0.5;
6662 overridecolor[2] = 0.1;
6664 if (!strcmp(value, "light_torch_small_walltorch"))
6669 overridecolor[0] = 1;
6670 overridecolor[1] = 0.5;
6671 overridecolor[2] = 0.1;
6675 else if (!strcmp("style", key))
6676 style = atoi(value);
6677 else if (!strcmp("skin", key))
6678 skin = (int)atof(value);
6679 else if (!strcmp("pflags", key))
6680 pflags = (int)atof(value);
6681 //else if (!strcmp("effects", key))
6682 // effects = (int)atof(value);
6683 else if (cl.worldmodel->type == mod_brushq3)
6685 if (!strcmp("scale", key))
6686 lightscale = atof(value);
6687 if (!strcmp("fade", key))
6688 fadescale = atof(value);
6693 if (lightscale <= 0)
6697 if (color[0] == color[1] && color[0] == color[2])
6699 color[0] *= overridecolor[0];
6700 color[1] *= overridecolor[1];
6701 color[2] *= overridecolor[2];
6703 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
6704 color[0] = color[0] * light[0];
6705 color[1] = color[1] * light[1];
6706 color[2] = color[2] * light[2];
6709 case LIGHTTYPE_MINUSX:
6711 case LIGHTTYPE_RECIPX:
6713 VectorScale(color, (1.0f / 16.0f), color);
6715 case LIGHTTYPE_RECIPXX:
6717 VectorScale(color, (1.0f / 16.0f), color);
6720 case LIGHTTYPE_NONE:
6724 case LIGHTTYPE_MINUSXX:
6727 VectorAdd(origin, originhack, origin);
6729 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);
6732 Mem_Free(entfiledata);
6736 static void R_Shadow_SetCursorLocationForView(void)
6739 vec3_t dest, endpos;
6741 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
6742 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true);
6743 if (trace.fraction < 1)
6745 dist = trace.fraction * r_editlights_cursordistance.value;
6746 push = r_editlights_cursorpushback.value;
6750 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
6751 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
6755 VectorClear( endpos );
6757 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6758 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6759 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6762 void R_Shadow_UpdateWorldLightSelection(void)
6764 if (r_editlights.integer)
6766 R_Shadow_SetCursorLocationForView();
6767 R_Shadow_SelectLightInView();
6770 R_Shadow_SelectLight(NULL);
6773 static void R_Shadow_EditLights_Clear_f(void)
6775 R_Shadow_ClearWorldLights();
6778 void R_Shadow_EditLights_Reload_f(void)
6782 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
6783 R_Shadow_ClearWorldLights();
6784 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
6786 R_Shadow_LoadWorldLights();
6787 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6788 R_Shadow_LoadLightsFile();
6790 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
6792 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6793 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6797 static void R_Shadow_EditLights_Save_f(void)
6801 R_Shadow_SaveWorldLights();
6804 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6806 R_Shadow_ClearWorldLights();
6807 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6810 static void R_Shadow_EditLights_ImportLightsFile_f(void)
6812 R_Shadow_ClearWorldLights();
6813 R_Shadow_LoadLightsFile();
6816 static void R_Shadow_EditLights_Spawn_f(void)
6819 if (!r_editlights.integer)
6821 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6824 if (Cmd_Argc() != 1)
6826 Con_Print("r_editlights_spawn does not take parameters\n");
6829 color[0] = color[1] = color[2] = 1;
6830 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6833 static void R_Shadow_EditLights_Edit_f(void)
6835 vec3_t origin, angles, color;
6836 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6837 int style, shadows, flags, normalmode, realtimemode;
6838 char cubemapname[MAX_INPUTLINE];
6839 if (!r_editlights.integer)
6841 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6844 if (!r_shadow_selectedlight)
6846 Con_Print("No selected light.\n");
6849 VectorCopy(r_shadow_selectedlight->origin, origin);
6850 VectorCopy(r_shadow_selectedlight->angles, angles);
6851 VectorCopy(r_shadow_selectedlight->color, color);
6852 radius = r_shadow_selectedlight->radius;
6853 style = r_shadow_selectedlight->style;
6854 if (r_shadow_selectedlight->cubemapname)
6855 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6858 shadows = r_shadow_selectedlight->shadow;
6859 corona = r_shadow_selectedlight->corona;
6860 coronasizescale = r_shadow_selectedlight->coronasizescale;
6861 ambientscale = r_shadow_selectedlight->ambientscale;
6862 diffusescale = r_shadow_selectedlight->diffusescale;
6863 specularscale = r_shadow_selectedlight->specularscale;
6864 flags = r_shadow_selectedlight->flags;
6865 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6866 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6867 if (!strcmp(Cmd_Argv(1), "origin"))
6869 if (Cmd_Argc() != 5)
6871 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6874 origin[0] = atof(Cmd_Argv(2));
6875 origin[1] = atof(Cmd_Argv(3));
6876 origin[2] = atof(Cmd_Argv(4));
6878 else if (!strcmp(Cmd_Argv(1), "originscale"))
6880 if (Cmd_Argc() != 5)
6882 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6885 origin[0] *= atof(Cmd_Argv(2));
6886 origin[1] *= atof(Cmd_Argv(3));
6887 origin[2] *= atof(Cmd_Argv(4));
6889 else if (!strcmp(Cmd_Argv(1), "originx"))
6891 if (Cmd_Argc() != 3)
6893 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6896 origin[0] = atof(Cmd_Argv(2));
6898 else if (!strcmp(Cmd_Argv(1), "originy"))
6900 if (Cmd_Argc() != 3)
6902 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6905 origin[1] = atof(Cmd_Argv(2));
6907 else if (!strcmp(Cmd_Argv(1), "originz"))
6909 if (Cmd_Argc() != 3)
6911 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6914 origin[2] = atof(Cmd_Argv(2));
6916 else if (!strcmp(Cmd_Argv(1), "move"))
6918 if (Cmd_Argc() != 5)
6920 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6923 origin[0] += atof(Cmd_Argv(2));
6924 origin[1] += atof(Cmd_Argv(3));
6925 origin[2] += atof(Cmd_Argv(4));
6927 else if (!strcmp(Cmd_Argv(1), "movex"))
6929 if (Cmd_Argc() != 3)
6931 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6934 origin[0] += atof(Cmd_Argv(2));
6936 else if (!strcmp(Cmd_Argv(1), "movey"))
6938 if (Cmd_Argc() != 3)
6940 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6943 origin[1] += atof(Cmd_Argv(2));
6945 else if (!strcmp(Cmd_Argv(1), "movez"))
6947 if (Cmd_Argc() != 3)
6949 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6952 origin[2] += atof(Cmd_Argv(2));
6954 else if (!strcmp(Cmd_Argv(1), "angles"))
6956 if (Cmd_Argc() != 5)
6958 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6961 angles[0] = atof(Cmd_Argv(2));
6962 angles[1] = atof(Cmd_Argv(3));
6963 angles[2] = atof(Cmd_Argv(4));
6965 else if (!strcmp(Cmd_Argv(1), "anglesx"))
6967 if (Cmd_Argc() != 3)
6969 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6972 angles[0] = atof(Cmd_Argv(2));
6974 else if (!strcmp(Cmd_Argv(1), "anglesy"))
6976 if (Cmd_Argc() != 3)
6978 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6981 angles[1] = atof(Cmd_Argv(2));
6983 else if (!strcmp(Cmd_Argv(1), "anglesz"))
6985 if (Cmd_Argc() != 3)
6987 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6990 angles[2] = atof(Cmd_Argv(2));
6992 else if (!strcmp(Cmd_Argv(1), "color"))
6994 if (Cmd_Argc() != 5)
6996 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
6999 color[0] = atof(Cmd_Argv(2));
7000 color[1] = atof(Cmd_Argv(3));
7001 color[2] = atof(Cmd_Argv(4));
7003 else if (!strcmp(Cmd_Argv(1), "radius"))
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), "colorscale"))
7014 if (Cmd_Argc() == 3)
7016 double scale = atof(Cmd_Argv(2));
7023 if (Cmd_Argc() != 5)
7025 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
7028 color[0] *= atof(Cmd_Argv(2));
7029 color[1] *= atof(Cmd_Argv(3));
7030 color[2] *= atof(Cmd_Argv(4));
7033 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
7035 if (Cmd_Argc() != 3)
7037 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7040 radius *= atof(Cmd_Argv(2));
7042 else if (!strcmp(Cmd_Argv(1), "style"))
7044 if (Cmd_Argc() != 3)
7046 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7049 style = atoi(Cmd_Argv(2));
7051 else if (!strcmp(Cmd_Argv(1), "cubemap"))
7055 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7058 if (Cmd_Argc() == 3)
7059 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
7063 else if (!strcmp(Cmd_Argv(1), "shadows"))
7065 if (Cmd_Argc() != 3)
7067 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7070 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7072 else if (!strcmp(Cmd_Argv(1), "corona"))
7074 if (Cmd_Argc() != 3)
7076 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7079 corona = atof(Cmd_Argv(2));
7081 else if (!strcmp(Cmd_Argv(1), "coronasize"))
7083 if (Cmd_Argc() != 3)
7085 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7088 coronasizescale = atof(Cmd_Argv(2));
7090 else if (!strcmp(Cmd_Argv(1), "ambient"))
7092 if (Cmd_Argc() != 3)
7094 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7097 ambientscale = atof(Cmd_Argv(2));
7099 else if (!strcmp(Cmd_Argv(1), "diffuse"))
7101 if (Cmd_Argc() != 3)
7103 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7106 diffusescale = atof(Cmd_Argv(2));
7108 else if (!strcmp(Cmd_Argv(1), "specular"))
7110 if (Cmd_Argc() != 3)
7112 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7115 specularscale = atof(Cmd_Argv(2));
7117 else if (!strcmp(Cmd_Argv(1), "normalmode"))
7119 if (Cmd_Argc() != 3)
7121 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7124 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7126 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
7128 if (Cmd_Argc() != 3)
7130 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7133 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7137 Con_Print("usage: r_editlights_edit [property] [value]\n");
7138 Con_Print("Selected light's properties:\n");
7139 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7140 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7141 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7142 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
7143 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
7144 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
7145 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
7146 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
7147 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
7148 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
7149 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
7150 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
7151 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
7152 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
7155 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
7156 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
7159 static void R_Shadow_EditLights_EditAll_f(void)
7162 dlight_t *light, *oldselected;
7165 if (!r_editlights.integer)
7167 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
7171 oldselected = r_shadow_selectedlight;
7172 // EditLights doesn't seem to have a "remove" command or something so:
7173 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7174 for (lightindex = 0;lightindex < range;lightindex++)
7176 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7179 R_Shadow_SelectLight(light);
7180 R_Shadow_EditLights_Edit_f();
7182 // return to old selected (to not mess editing once selection is locked)
7183 R_Shadow_SelectLight(oldselected);
7186 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
7188 int lightnumber, lightcount;
7189 size_t lightindex, range;
7194 if (!r_editlights.integer)
7197 // update cvars so QC can query them
7198 if (r_shadow_selectedlight)
7200 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7201 Cvar_SetQuick(&r_editlights_current_origin, temp);
7202 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7203 Cvar_SetQuick(&r_editlights_current_angles, temp);
7204 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7205 Cvar_SetQuick(&r_editlights_current_color, temp);
7206 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
7207 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
7208 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
7209 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
7210 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
7211 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
7212 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
7213 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
7214 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
7215 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
7216 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
7219 // draw properties on screen
7220 if (!r_editlights_drawproperties.integer)
7222 x = vid_conwidth.value - 320;
7224 DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
7227 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7228 for (lightindex = 0;lightindex < range;lightindex++)
7230 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7233 if (light == r_shadow_selectedlight)
7234 lightnumber = (int)lightindex;
7237 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;
7238 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;
7240 if (r_shadow_selectedlight == NULL)
7242 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;
7243 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;
7244 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;
7245 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;
7246 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;
7247 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;
7248 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;
7249 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;
7250 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;
7251 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;
7252 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;
7253 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;
7254 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;
7255 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;
7256 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;
7258 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;
7259 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;
7260 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;
7261 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;
7262 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;
7263 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;
7264 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;
7265 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;
7266 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;
7267 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;
7270 static void R_Shadow_EditLights_ToggleShadow_f(void)
7272 if (!r_editlights.integer)
7274 Con_Print("Cannot spawn 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_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);
7285 static void R_Shadow_EditLights_ToggleCorona_f(void)
7287 if (!r_editlights.integer)
7289 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7292 if (!r_shadow_selectedlight)
7294 Con_Print("No selected light.\n");
7297 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);
7300 static void R_Shadow_EditLights_Remove_f(void)
7302 if (!r_editlights.integer)
7304 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
7307 if (!r_shadow_selectedlight)
7309 Con_Print("No selected light.\n");
7312 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
7313 r_shadow_selectedlight = NULL;
7316 static void R_Shadow_EditLights_Help_f(void)
7319 "Documentation on r_editlights system:\n"
7321 "r_editlights : enable/disable editing mode\n"
7322 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
7323 "r_editlights_cursorpushback : push back cursor this far from surface\n"
7324 "r_editlights_cursorpushoff : push cursor off surface this far\n"
7325 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
7326 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
7328 "r_editlights_help : this help\n"
7329 "r_editlights_clear : remove all lights\n"
7330 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
7331 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
7332 "r_editlights_save : save to .rtlights file\n"
7333 "r_editlights_spawn : create a light with default settings\n"
7334 "r_editlights_edit command : edit selected light - more documentation below\n"
7335 "r_editlights_remove : remove selected light\n"
7336 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
7337 "r_editlights_importlightentitiesfrommap : reload light entities\n"
7338 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
7340 "origin x y z : set light location\n"
7341 "originx x: set x component of light location\n"
7342 "originy y: set y component of light location\n"
7343 "originz z: set z component of light location\n"
7344 "move x y z : adjust light location\n"
7345 "movex x: adjust x component of light location\n"
7346 "movey y: adjust y component of light location\n"
7347 "movez z: adjust z component of light location\n"
7348 "angles x y z : set light angles\n"
7349 "anglesx x: set x component of light angles\n"
7350 "anglesy y: set y component of light angles\n"
7351 "anglesz z: set z component of light angles\n"
7352 "color r g b : set color of light (can be brighter than 1 1 1)\n"
7353 "radius radius : set radius (size) of light\n"
7354 "colorscale grey : multiply color of light (1 does nothing)\n"
7355 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
7356 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
7357 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
7358 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
7359 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
7360 "cubemap basename : set filter cubemap of light\n"
7361 "shadows 1/0 : turn on/off shadows\n"
7362 "corona n : set corona intensity\n"
7363 "coronasize n : set corona size (0-1)\n"
7364 "ambient n : set ambient intensity (0-1)\n"
7365 "diffuse n : set diffuse intensity (0-1)\n"
7366 "specular n : set specular intensity (0-1)\n"
7367 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
7368 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
7369 "<nothing> : print light properties to console\n"
7373 static void R_Shadow_EditLights_CopyInfo_f(void)
7375 if (!r_editlights.integer)
7377 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
7380 if (!r_shadow_selectedlight)
7382 Con_Print("No selected light.\n");
7385 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
7386 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
7387 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
7388 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
7389 if (r_shadow_selectedlight->cubemapname)
7390 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
7392 r_shadow_bufferlight.cubemapname[0] = 0;
7393 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
7394 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
7395 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
7396 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
7397 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
7398 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
7399 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
7402 static void R_Shadow_EditLights_PasteInfo_f(void)
7404 if (!r_editlights.integer)
7406 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
7409 if (!r_shadow_selectedlight)
7411 Con_Print("No selected light.\n");
7414 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);
7417 static void R_Shadow_EditLights_Lock_f(void)
7419 if (!r_editlights.integer)
7421 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
7424 if (r_editlights_lockcursor)
7426 r_editlights_lockcursor = false;
7429 if (!r_shadow_selectedlight)
7431 Con_Print("No selected light to lock on.\n");
7434 r_editlights_lockcursor = true;
7437 static void R_Shadow_EditLights_Init(void)
7439 Cvar_RegisterVariable(&r_editlights);
7440 Cvar_RegisterVariable(&r_editlights_cursordistance);
7441 Cvar_RegisterVariable(&r_editlights_cursorpushback);
7442 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
7443 Cvar_RegisterVariable(&r_editlights_cursorgrid);
7444 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
7445 Cvar_RegisterVariable(&r_editlights_drawproperties);
7446 Cvar_RegisterVariable(&r_editlights_current_origin);
7447 Cvar_RegisterVariable(&r_editlights_current_angles);
7448 Cvar_RegisterVariable(&r_editlights_current_color);
7449 Cvar_RegisterVariable(&r_editlights_current_radius);
7450 Cvar_RegisterVariable(&r_editlights_current_corona);
7451 Cvar_RegisterVariable(&r_editlights_current_coronasize);
7452 Cvar_RegisterVariable(&r_editlights_current_style);
7453 Cvar_RegisterVariable(&r_editlights_current_shadows);
7454 Cvar_RegisterVariable(&r_editlights_current_cubemap);
7455 Cvar_RegisterVariable(&r_editlights_current_ambient);
7456 Cvar_RegisterVariable(&r_editlights_current_diffuse);
7457 Cvar_RegisterVariable(&r_editlights_current_specular);
7458 Cvar_RegisterVariable(&r_editlights_current_normalmode);
7459 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
7460 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
7461 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
7462 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)");
7463 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
7464 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
7465 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
7466 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)");
7467 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
7468 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
7469 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
7470 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
7471 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
7472 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
7473 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)");
7474 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
7480 =============================================================================
7484 =============================================================================
7487 void R_LightPoint(float *color, const vec3_t p, const int flags)
7489 int i, numlights, flag;
7490 float f, relativepoint[3], dist, dist2, lightradius2;
7495 if (r_fullbright.integer)
7497 VectorSet(color, 1, 1, 1);
7503 if (flags & LP_LIGHTMAP)
7505 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7507 VectorClear(diffuse);
7508 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, color, diffuse, n);
7509 VectorAdd(color, diffuse, color);
7512 VectorSet(color, 1, 1, 1);
7513 color[0] += r_refdef.scene.ambient;
7514 color[1] += r_refdef.scene.ambient;
7515 color[2] += r_refdef.scene.ambient;
7518 if (flags & LP_RTWORLD)
7520 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7521 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7522 for (i = 0; i < numlights; i++)
7524 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7527 light = &dlight->rtlight;
7528 if (!(light->flags & flag))
7531 lightradius2 = light->radius * light->radius;
7532 VectorSubtract(light->shadoworigin, p, relativepoint);
7533 dist2 = VectorLength2(relativepoint);
7534 if (dist2 >= lightradius2)
7536 dist = sqrt(dist2) / light->radius;
7537 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7540 // todo: add to both ambient and diffuse
7541 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)
7542 VectorMA(color, f, light->currentcolor, color);
7545 if (flags & LP_DYNLIGHT)
7548 for (i = 0;i < r_refdef.scene.numlights;i++)
7550 light = r_refdef.scene.lights[i];
7552 lightradius2 = light->radius * light->radius;
7553 VectorSubtract(light->shadoworigin, p, relativepoint);
7554 dist2 = VectorLength2(relativepoint);
7555 if (dist2 >= lightradius2)
7557 dist = sqrt(dist2) / light->radius;
7558 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7561 // todo: add to both ambient and diffuse
7562 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)
7563 VectorMA(color, f, light->color, color);
7568 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
7570 int i, numlights, flag;
7573 float relativepoint[3];
7582 if (r_fullbright.integer)
7584 VectorSet(ambient, 1, 1, 1);
7585 VectorClear(diffuse);
7586 VectorClear(lightdir);
7590 if (flags == LP_LIGHTMAP)
7592 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7593 VectorClear(diffuse);
7594 VectorClear(lightdir);
7595 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7596 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
7598 VectorSet(ambient, 1, 1, 1);
7602 memset(sample, 0, sizeof(sample));
7603 VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7605 if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7608 VectorClear(tempambient);
7610 VectorClear(relativepoint);
7611 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
7612 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
7613 VectorScale(color, r_refdef.lightmapintensity, color);
7614 VectorAdd(sample, tempambient, sample);
7615 VectorMA(sample , 0.5f , color, sample );
7616 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7617 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7618 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7619 // calculate a weighted average light direction as well
7620 intensity = VectorLength(color);
7621 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7624 if (flags & LP_RTWORLD)
7626 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7627 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7628 for (i = 0; i < numlights; i++)
7630 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7633 light = &dlight->rtlight;
7634 if (!(light->flags & flag))
7637 lightradius2 = light->radius * light->radius;
7638 VectorSubtract(light->shadoworigin, p, relativepoint);
7639 dist2 = VectorLength2(relativepoint);
7640 if (dist2 >= lightradius2)
7642 dist = sqrt(dist2) / light->radius;
7643 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
7644 if (intensity <= 0.0f)
7646 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)
7648 // scale down intensity to add to both ambient and diffuse
7649 //intensity *= 0.5f;
7650 VectorNormalize(relativepoint);
7651 VectorScale(light->currentcolor, intensity, color);
7652 VectorMA(sample , 0.5f , color, sample );
7653 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7654 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7655 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7656 // calculate a weighted average light direction as well
7657 intensity *= VectorLength(color);
7658 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7660 // FIXME: sample bouncegrid too!
7663 if (flags & LP_DYNLIGHT)
7666 for (i = 0;i < r_refdef.scene.numlights;i++)
7668 light = r_refdef.scene.lights[i];
7670 lightradius2 = light->radius * light->radius;
7671 VectorSubtract(light->shadoworigin, p, relativepoint);
7672 dist2 = VectorLength2(relativepoint);
7673 if (dist2 >= lightradius2)
7675 dist = sqrt(dist2) / light->radius;
7676 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
7677 if (intensity <= 0.0f)
7679 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)
7681 // scale down intensity to add to both ambient and diffuse
7682 //intensity *= 0.5f;
7683 VectorNormalize(relativepoint);
7684 VectorScale(light->currentcolor, intensity, color);
7685 VectorMA(sample , 0.5f , color, sample );
7686 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7687 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7688 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7689 // calculate a weighted average light direction as well
7690 intensity *= VectorLength(color);
7691 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7695 // calculate the direction we'll use to reduce the sample to a directional light source
7696 VectorCopy(sample + 12, dir);
7697 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
7698 VectorNormalize(dir);
7699 // extract the diffuse color along the chosen direction and scale it
7700 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
7701 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
7702 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
7703 // subtract some of diffuse from ambient
7704 VectorMA(sample, -0.333f, diffuse, ambient);
7705 // store the normalized lightdir
7706 VectorCopy(dir, lightdir);