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_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)"};
341 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"};
342 cvar_t r_shadow_bouncegrid_dynamic_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_directionalshading", "0", "use diffuse shading rather than ambient, 3D texture becomes 8x as many pixels to hold the additional data"};
343 cvar_t r_shadow_bouncegrid_dynamic_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
344 cvar_t r_shadow_bouncegrid_dynamic_energyperphoton = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_energyperphoton", "10000", "amount of light that one photon should represent"};
345 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)"};
346 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)"};
347 cvar_t r_shadow_bouncegrid_dynamic_maxphotons = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_maxphotons", "25000", "upper bound on photons to shoot per update, divided proportionately between lights - normally the number of photons is calculated by energyperphoton"};
348 cvar_t r_shadow_bouncegrid_dynamic_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_spacing", "64", "unit size of bouncegrid pixel"};
349 cvar_t r_shadow_bouncegrid_dynamic_stablerandom = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_stablerandom", "1", "make particle distribution consistent from frame to frame"};
350 cvar_t r_shadow_bouncegrid_dynamic_updateinterval = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_updateinterval", "0", "update bouncegrid texture once per this many seconds, useful values are 0, 0.05, or 1000000"};
351 cvar_t r_shadow_bouncegrid_dynamic_x = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_x", "64", "maximum texture size of bouncegrid on X axis"};
352 cvar_t r_shadow_bouncegrid_dynamic_y = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_y", "64", "maximum texture size of bouncegrid on Y axis"};
353 cvar_t r_shadow_bouncegrid_dynamic_z = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_z", "32", "maximum texture size of bouncegrid on Z axis"};
354 cvar_t r_shadow_bouncegrid_floatcolors = {CVAR_SAVE, "r_shadow_bouncegrid_floatcolors", "1", "upload texture as RGBA16F (or RGBA32F when set to 2) rather than RGBA8 format - this gives more dynamic range and accuracy"};
355 cvar_t r_shadow_bouncegrid_includedirectlighting = {CVAR_SAVE, "r_shadow_bouncegrid_includedirectlighting", "0", "allows direct lighting to be recorded, not just indirect (gives an effect somewhat like r_shadow_realtime_world_lightmaps)"};
356 cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
357 cvar_t r_shadow_bouncegrid_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"};
358 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "0.25", "brightness of particles contributing to bouncegrid texture"};
359 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"};
360 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"};
361 cvar_t r_shadow_bouncegrid_static = {CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
362 cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
363 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"};
364 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"};
365 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"};
366 cvar_t r_shadow_bouncegrid_static_maxphotons = {CVAR_SAVE, "r_shadow_bouncegrid_static_maxphotons", "250000", "upper bound on photons in static mode"};
367 cvar_t r_shadow_bouncegrid_static_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_static_spacing", "64", "unit size of bouncegrid pixel when in static mode"};
368 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
369 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"};
370 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!"};
371 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
372 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
373 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
374 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
375 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
376 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
377 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
378 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
379 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
380 cvar_t r_editlights_drawproperties = {0, "r_editlights_drawproperties", "1", "draw properties of currently selected light"};
381 cvar_t r_editlights_current_origin = {0, "r_editlights_current_origin", "0 0 0", "origin of selected light"};
382 cvar_t r_editlights_current_angles = {0, "r_editlights_current_angles", "0 0 0", "angles of selected light"};
383 cvar_t r_editlights_current_color = {0, "r_editlights_current_color", "1 1 1", "color of selected light"};
384 cvar_t r_editlights_current_radius = {0, "r_editlights_current_radius", "0", "radius of selected light"};
385 cvar_t r_editlights_current_corona = {0, "r_editlights_current_corona", "0", "corona intensity of selected light"};
386 cvar_t r_editlights_current_coronasize = {0, "r_editlights_current_coronasize", "0", "corona size of selected light"};
387 cvar_t r_editlights_current_style = {0, "r_editlights_current_style", "0", "style of selected light"};
388 cvar_t r_editlights_current_shadows = {0, "r_editlights_current_shadows", "0", "shadows flag of selected light"};
389 cvar_t r_editlights_current_cubemap = {0, "r_editlights_current_cubemap", "0", "cubemap of selected light"};
390 cvar_t r_editlights_current_ambient = {0, "r_editlights_current_ambient", "0", "ambient intensity of selected light"};
391 cvar_t r_editlights_current_diffuse = {0, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"};
392 cvar_t r_editlights_current_specular = {0, "r_editlights_current_specular", "1", "specular intensity of selected light"};
393 cvar_t r_editlights_current_normalmode = {0, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"};
394 cvar_t r_editlights_current_realtimemode = {0, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"};
396 r_shadow_bouncegrid_state_t r_shadow_bouncegrid_state;
398 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
399 #define ATTENTABLESIZE 256
400 // 1D gradient, 2D circle and 3D sphere attenuation textures
401 #define ATTEN1DSIZE 32
402 #define ATTEN2DSIZE 64
403 #define ATTEN3DSIZE 32
405 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
406 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
407 static float r_shadow_attentable[ATTENTABLESIZE+1];
409 rtlight_t *r_shadow_compilingrtlight;
410 static memexpandablearray_t r_shadow_worldlightsarray;
411 dlight_t *r_shadow_selectedlight;
412 dlight_t r_shadow_bufferlight;
413 vec3_t r_editlights_cursorlocation;
414 qboolean r_editlights_lockcursor;
416 extern int con_vislines;
418 void R_Shadow_UncompileWorldLights(void);
419 void R_Shadow_ClearWorldLights(void);
420 void R_Shadow_SaveWorldLights(void);
421 void R_Shadow_LoadWorldLights(void);
422 void R_Shadow_LoadLightsFile(void);
423 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
424 void R_Shadow_EditLights_Reload_f(void);
425 void R_Shadow_ValidateCvars(void);
426 static void R_Shadow_MakeTextures(void);
428 #define EDLIGHTSPRSIZE 8
429 skinframe_t *r_editlights_sprcursor;
430 skinframe_t *r_editlights_sprlight;
431 skinframe_t *r_editlights_sprnoshadowlight;
432 skinframe_t *r_editlights_sprcubemaplight;
433 skinframe_t *r_editlights_sprcubemapnoshadowlight;
434 skinframe_t *r_editlights_sprselection;
436 static void R_Shadow_DrawModelShadowMaps(void);
437 static void R_Shadow_MakeShadowMap(int texturesize);
438 static void R_Shadow_MakeVSDCT(void);
439 static void R_Shadow_SetShadowMode(void)
441 r_shadow_shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
442 r_shadow_shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
443 r_shadow_shadowmapmaxsize = bound(r_shadow_shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, r_shadow_shadowmaptexturesize / 8);
444 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
445 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
446 r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
447 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
448 r_shadow_shadowmapsampler = false;
449 r_shadow_shadowmappcf = 0;
450 r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
451 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
452 Mod_AllocLightmap_Init(&r_shadow_shadowmapatlas_state, r_main_mempool, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize);
453 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
455 switch(vid.renderpath)
457 case RENDERPATH_GL20:
458 if(r_shadow_shadowmapfilterquality < 0)
460 if (!r_fb.usedepthtextures)
461 r_shadow_shadowmappcf = 1;
462 else if((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && vid.support.arb_shadow && r_shadow_shadowmapshadowsampler)
464 r_shadow_shadowmapsampler = true;
465 r_shadow_shadowmappcf = 1;
467 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
468 r_shadow_shadowmappcf = 1;
469 else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa"))
470 r_shadow_shadowmappcf = 1;
472 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
476 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
477 switch (r_shadow_shadowmapfilterquality)
482 r_shadow_shadowmappcf = 1;
485 r_shadow_shadowmappcf = 1;
488 r_shadow_shadowmappcf = 2;
492 if (!r_fb.usedepthtextures)
493 r_shadow_shadowmapsampler = false;
494 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
496 case RENDERPATH_D3D9:
497 case RENDERPATH_D3D10:
498 case RENDERPATH_D3D11:
499 case RENDERPATH_SOFT:
500 r_shadow_shadowmapsampler = false;
501 r_shadow_shadowmappcf = 1;
502 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
504 case RENDERPATH_GL11:
505 case RENDERPATH_GL13:
506 case RENDERPATH_GLES1:
507 case RENDERPATH_GLES2:
512 if(R_CompileShader_CheckStaticParms())
516 qboolean R_Shadow_ShadowMappingEnabled(void)
518 switch (r_shadow_shadowmode)
520 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
527 static void R_Shadow_FreeShadowMaps(void)
529 Mod_AllocLightmap_Free(&r_shadow_shadowmapatlas_state);
531 R_Shadow_SetShadowMode();
533 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
537 if (r_shadow_shadowmap2ddepthtexture)
538 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
539 r_shadow_shadowmap2ddepthtexture = NULL;
541 if (r_shadow_shadowmap2ddepthbuffer)
542 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
543 r_shadow_shadowmap2ddepthbuffer = NULL;
545 if (r_shadow_shadowmapvsdcttexture)
546 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
547 r_shadow_shadowmapvsdcttexture = NULL;
550 static void r_shadow_start(void)
552 // allocate vertex processing arrays
553 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
554 r_shadow_bouncegrid_state.maxsplatpaths = 16384;
555 r_shadow_attenuationgradienttexture = NULL;
556 r_shadow_attenuation2dtexture = NULL;
557 r_shadow_attenuation3dtexture = NULL;
558 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
559 r_shadow_shadowmap2ddepthtexture = NULL;
560 r_shadow_shadowmap2ddepthbuffer = NULL;
561 r_shadow_shadowmapvsdcttexture = NULL;
562 r_shadow_shadowmapmaxsize = 0;
563 r_shadow_shadowmaptexturesize = 0;
564 r_shadow_shadowmapfilterquality = -1;
565 r_shadow_shadowmapdepthbits = 0;
566 r_shadow_shadowmapvsdct = false;
567 r_shadow_shadowmapsampler = false;
568 r_shadow_shadowmappcf = 0;
571 R_Shadow_FreeShadowMaps();
573 r_shadow_texturepool = NULL;
574 r_shadow_filters_texturepool = NULL;
575 R_Shadow_ValidateCvars();
576 R_Shadow_MakeTextures();
577 r_shadow_scenemaxlights = 0;
578 r_shadow_scenenumlights = 0;
579 r_shadow_scenelightlist = NULL;
580 maxshadowtriangles = 0;
581 shadowelements = NULL;
582 maxshadowvertices = 0;
583 shadowvertex3f = NULL;
591 shadowmarklist = NULL;
596 shadowsideslist = NULL;
597 r_shadow_buffer_numleafpvsbytes = 0;
598 r_shadow_buffer_visitingleafpvs = NULL;
599 r_shadow_buffer_leafpvs = NULL;
600 r_shadow_buffer_leaflist = NULL;
601 r_shadow_buffer_numsurfacepvsbytes = 0;
602 r_shadow_buffer_surfacepvs = NULL;
603 r_shadow_buffer_surfacelist = NULL;
604 r_shadow_buffer_surfacesides = NULL;
605 r_shadow_buffer_numshadowtrispvsbytes = 0;
606 r_shadow_buffer_shadowtrispvs = NULL;
607 r_shadow_buffer_numlighttrispvsbytes = 0;
608 r_shadow_buffer_lighttrispvs = NULL;
610 r_shadow_usingdeferredprepass = false;
611 r_shadow_prepass_width = r_shadow_prepass_height = 0;
613 // determine renderpath specific capabilities, we don't need to figure
614 // these out per frame...
615 switch(vid.renderpath)
617 case RENDERPATH_GL20:
618 r_shadow_bouncegrid_state.allowdirectionalshading = true;
619 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
621 case RENDERPATH_GLES2:
622 // for performance reasons, do not use directional shading on GLES devices
623 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
625 // these renderpaths do not currently have the code to display the bouncegrid, so disable it on them...
626 case RENDERPATH_GL11:
627 case RENDERPATH_GL13:
628 case RENDERPATH_GLES1:
629 case RENDERPATH_SOFT:
630 case RENDERPATH_D3D9:
631 case RENDERPATH_D3D10:
632 case RENDERPATH_D3D11:
637 static void R_Shadow_FreeDeferred(void);
638 static void r_shadow_shutdown(void)
641 R_Shadow_UncompileWorldLights();
643 R_Shadow_FreeShadowMaps();
645 r_shadow_usingdeferredprepass = false;
646 if (r_shadow_prepass_width)
647 R_Shadow_FreeDeferred();
648 r_shadow_prepass_width = r_shadow_prepass_height = 0;
651 r_shadow_scenemaxlights = 0;
652 r_shadow_scenenumlights = 0;
653 if (r_shadow_scenelightlist)
654 Mem_Free(r_shadow_scenelightlist);
655 r_shadow_scenelightlist = NULL;
656 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
657 r_shadow_attenuationgradienttexture = NULL;
658 r_shadow_attenuation2dtexture = NULL;
659 r_shadow_attenuation3dtexture = NULL;
660 R_FreeTexturePool(&r_shadow_texturepool);
661 R_FreeTexturePool(&r_shadow_filters_texturepool);
662 maxshadowtriangles = 0;
664 Mem_Free(shadowelements);
665 shadowelements = NULL;
667 Mem_Free(shadowvertex3f);
668 shadowvertex3f = NULL;
671 Mem_Free(vertexupdate);
674 Mem_Free(vertexremap);
680 Mem_Free(shadowmark);
683 Mem_Free(shadowmarklist);
684 shadowmarklist = NULL;
689 Mem_Free(shadowsides);
692 Mem_Free(shadowsideslist);
693 shadowsideslist = NULL;
694 r_shadow_buffer_numleafpvsbytes = 0;
695 if (r_shadow_buffer_visitingleafpvs)
696 Mem_Free(r_shadow_buffer_visitingleafpvs);
697 r_shadow_buffer_visitingleafpvs = NULL;
698 if (r_shadow_buffer_leafpvs)
699 Mem_Free(r_shadow_buffer_leafpvs);
700 r_shadow_buffer_leafpvs = NULL;
701 if (r_shadow_buffer_leaflist)
702 Mem_Free(r_shadow_buffer_leaflist);
703 r_shadow_buffer_leaflist = NULL;
704 r_shadow_buffer_numsurfacepvsbytes = 0;
705 if (r_shadow_buffer_surfacepvs)
706 Mem_Free(r_shadow_buffer_surfacepvs);
707 r_shadow_buffer_surfacepvs = NULL;
708 if (r_shadow_buffer_surfacelist)
709 Mem_Free(r_shadow_buffer_surfacelist);
710 r_shadow_buffer_surfacelist = NULL;
711 if (r_shadow_buffer_surfacesides)
712 Mem_Free(r_shadow_buffer_surfacesides);
713 r_shadow_buffer_surfacesides = NULL;
714 r_shadow_buffer_numshadowtrispvsbytes = 0;
715 if (r_shadow_buffer_shadowtrispvs)
716 Mem_Free(r_shadow_buffer_shadowtrispvs);
717 r_shadow_buffer_numlighttrispvsbytes = 0;
718 if (r_shadow_buffer_lighttrispvs)
719 Mem_Free(r_shadow_buffer_lighttrispvs);
722 static void r_shadow_newmap(void)
724 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
725 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
726 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
727 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
728 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
729 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
730 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
731 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
732 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
733 R_Shadow_EditLights_Reload_f();
736 void R_Shadow_Init(void)
738 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
739 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
740 Cvar_RegisterVariable(&r_shadow_usebihculling);
741 Cvar_RegisterVariable(&r_shadow_usenormalmap);
742 Cvar_RegisterVariable(&r_shadow_debuglight);
743 Cvar_RegisterVariable(&r_shadow_deferred);
744 Cvar_RegisterVariable(&r_shadow_gloss);
745 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
746 Cvar_RegisterVariable(&r_shadow_glossintensity);
747 Cvar_RegisterVariable(&r_shadow_glossexponent);
748 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
749 Cvar_RegisterVariable(&r_shadow_glossexact);
750 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
751 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
752 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
753 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
754 Cvar_RegisterVariable(&r_shadow_projectdistance);
755 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
756 Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
757 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
758 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
759 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
760 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
761 Cvar_RegisterVariable(&r_shadow_realtime_world);
762 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
763 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
764 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
765 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
766 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
767 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
768 Cvar_RegisterVariable(&r_shadow_scissor);
769 Cvar_RegisterVariable(&r_shadow_shadowmapping);
770 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
771 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
772 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
773 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
774 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
775 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
776 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
777 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturesize);
778 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
779 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
780 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
781 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
782 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
783 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
784 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
785 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
786 Cvar_RegisterVariable(&r_shadow_polygonfactor);
787 Cvar_RegisterVariable(&r_shadow_polygonoffset);
788 Cvar_RegisterVariable(&r_shadow_texture3d);
789 Cvar_RegisterVariable(&r_shadow_bouncegrid);
790 Cvar_RegisterVariable(&r_shadow_bouncegrid_blur);
791 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
792 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_culllightpaths);
793 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_directionalshading);
794 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_dlightparticlemultiplier);
795 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_hitmodels);
796 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_energyperphoton);
797 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_lightradiusscale);
798 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxbounce);
799 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxphotons);
800 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_spacing);
801 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_stablerandom);
802 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_updateinterval);
803 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_x);
804 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_y);
805 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_z);
806 Cvar_RegisterVariable(&r_shadow_bouncegrid_floatcolors);
807 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
808 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
809 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize);
810 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
811 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
812 Cvar_RegisterVariable(&r_shadow_bouncegrid_sortlightpaths);
813 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
814 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_spacing);
815 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
816 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
817 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
818 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxphotons);
819 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_energyperphoton);
820 Cvar_RegisterVariable(&r_coronas);
821 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
822 Cvar_RegisterVariable(&r_coronas_occlusionquery);
823 Cvar_RegisterVariable(&gl_flashblend);
824 Cvar_RegisterVariable(&gl_ext_separatestencil);
825 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
826 R_Shadow_EditLights_Init();
827 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
828 r_shadow_scenemaxlights = 0;
829 r_shadow_scenenumlights = 0;
830 r_shadow_scenelightlist = NULL;
831 maxshadowtriangles = 0;
832 shadowelements = NULL;
833 maxshadowvertices = 0;
834 shadowvertex3f = NULL;
842 shadowmarklist = NULL;
847 shadowsideslist = NULL;
848 r_shadow_buffer_numleafpvsbytes = 0;
849 r_shadow_buffer_visitingleafpvs = NULL;
850 r_shadow_buffer_leafpvs = NULL;
851 r_shadow_buffer_leaflist = NULL;
852 r_shadow_buffer_numsurfacepvsbytes = 0;
853 r_shadow_buffer_surfacepvs = NULL;
854 r_shadow_buffer_surfacelist = NULL;
855 r_shadow_buffer_surfacesides = NULL;
856 r_shadow_buffer_shadowtrispvs = NULL;
857 r_shadow_buffer_lighttrispvs = NULL;
858 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
861 matrix4x4_t matrix_attenuationxyz =
864 {0.5, 0.0, 0.0, 0.5},
865 {0.0, 0.5, 0.0, 0.5},
866 {0.0, 0.0, 0.5, 0.5},
871 matrix4x4_t matrix_attenuationz =
874 {0.0, 0.0, 0.5, 0.5},
875 {0.0, 0.0, 0.0, 0.5},
876 {0.0, 0.0, 0.0, 0.5},
881 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
883 numvertices = ((numvertices + 255) & ~255) * vertscale;
884 numtriangles = ((numtriangles + 255) & ~255) * triscale;
885 // make sure shadowelements is big enough for this volume
886 if (maxshadowtriangles < numtriangles)
888 maxshadowtriangles = numtriangles;
890 Mem_Free(shadowelements);
891 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
893 // make sure shadowvertex3f is big enough for this volume
894 if (maxshadowvertices < numvertices)
896 maxshadowvertices = numvertices;
898 Mem_Free(shadowvertex3f);
899 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
903 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
905 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
906 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
907 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
908 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
909 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
911 if (r_shadow_buffer_visitingleafpvs)
912 Mem_Free(r_shadow_buffer_visitingleafpvs);
913 if (r_shadow_buffer_leafpvs)
914 Mem_Free(r_shadow_buffer_leafpvs);
915 if (r_shadow_buffer_leaflist)
916 Mem_Free(r_shadow_buffer_leaflist);
917 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
918 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
919 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
920 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
922 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
924 if (r_shadow_buffer_surfacepvs)
925 Mem_Free(r_shadow_buffer_surfacepvs);
926 if (r_shadow_buffer_surfacelist)
927 Mem_Free(r_shadow_buffer_surfacelist);
928 if (r_shadow_buffer_surfacesides)
929 Mem_Free(r_shadow_buffer_surfacesides);
930 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
931 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
932 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
933 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
935 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
937 if (r_shadow_buffer_shadowtrispvs)
938 Mem_Free(r_shadow_buffer_shadowtrispvs);
939 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
940 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
942 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
944 if (r_shadow_buffer_lighttrispvs)
945 Mem_Free(r_shadow_buffer_lighttrispvs);
946 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
947 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
951 void R_Shadow_PrepareShadowMark(int numtris)
953 // make sure shadowmark is big enough for this volume
954 if (maxshadowmark < numtris)
956 maxshadowmark = numtris;
958 Mem_Free(shadowmark);
960 Mem_Free(shadowmarklist);
961 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
962 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
966 // if shadowmarkcount wrapped we clear the array and adjust accordingly
967 if (shadowmarkcount == 0)
970 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
975 void R_Shadow_PrepareShadowSides(int numtris)
977 if (maxshadowsides < numtris)
979 maxshadowsides = numtris;
981 Mem_Free(shadowsides);
983 Mem_Free(shadowsideslist);
984 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
985 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
990 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)
993 int outtriangles = 0, outvertices = 0;
996 float ratio, direction[3], projectvector[3];
998 if (projectdirection)
999 VectorScale(projectdirection, projectdistance, projectvector);
1001 VectorClear(projectvector);
1003 // create the vertices
1004 if (projectdirection)
1006 for (i = 0;i < numshadowmarktris;i++)
1008 element = inelement3i + shadowmarktris[i] * 3;
1009 for (j = 0;j < 3;j++)
1011 if (vertexupdate[element[j]] != vertexupdatenum)
1013 vertexupdate[element[j]] = vertexupdatenum;
1014 vertexremap[element[j]] = outvertices;
1015 vertex = invertex3f + element[j] * 3;
1016 // project one copy of the vertex according to projectvector
1017 VectorCopy(vertex, outvertex3f);
1018 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1027 for (i = 0;i < numshadowmarktris;i++)
1029 element = inelement3i + shadowmarktris[i] * 3;
1030 for (j = 0;j < 3;j++)
1032 if (vertexupdate[element[j]] != vertexupdatenum)
1034 vertexupdate[element[j]] = vertexupdatenum;
1035 vertexremap[element[j]] = outvertices;
1036 vertex = invertex3f + element[j] * 3;
1037 // project one copy of the vertex to the sphere radius of the light
1038 // (FIXME: would projecting it to the light box be better?)
1039 VectorSubtract(vertex, projectorigin, direction);
1040 ratio = projectdistance / VectorLength(direction);
1041 VectorCopy(vertex, outvertex3f);
1042 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1050 if (r_shadow_frontsidecasting.integer)
1052 for (i = 0;i < numshadowmarktris;i++)
1054 int remappedelement[3];
1056 const int *neighbortriangle;
1058 markindex = shadowmarktris[i] * 3;
1059 element = inelement3i + markindex;
1060 neighbortriangle = inneighbor3i + markindex;
1061 // output the front and back triangles
1062 outelement3i[0] = vertexremap[element[0]];
1063 outelement3i[1] = vertexremap[element[1]];
1064 outelement3i[2] = vertexremap[element[2]];
1065 outelement3i[3] = vertexremap[element[2]] + 1;
1066 outelement3i[4] = vertexremap[element[1]] + 1;
1067 outelement3i[5] = vertexremap[element[0]] + 1;
1071 // output the sides (facing outward from this triangle)
1072 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1074 remappedelement[0] = vertexremap[element[0]];
1075 remappedelement[1] = vertexremap[element[1]];
1076 outelement3i[0] = remappedelement[1];
1077 outelement3i[1] = remappedelement[0];
1078 outelement3i[2] = remappedelement[0] + 1;
1079 outelement3i[3] = remappedelement[1];
1080 outelement3i[4] = remappedelement[0] + 1;
1081 outelement3i[5] = remappedelement[1] + 1;
1086 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1088 remappedelement[1] = vertexremap[element[1]];
1089 remappedelement[2] = vertexremap[element[2]];
1090 outelement3i[0] = remappedelement[2];
1091 outelement3i[1] = remappedelement[1];
1092 outelement3i[2] = remappedelement[1] + 1;
1093 outelement3i[3] = remappedelement[2];
1094 outelement3i[4] = remappedelement[1] + 1;
1095 outelement3i[5] = remappedelement[2] + 1;
1100 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1102 remappedelement[0] = vertexremap[element[0]];
1103 remappedelement[2] = vertexremap[element[2]];
1104 outelement3i[0] = remappedelement[0];
1105 outelement3i[1] = remappedelement[2];
1106 outelement3i[2] = remappedelement[2] + 1;
1107 outelement3i[3] = remappedelement[0];
1108 outelement3i[4] = remappedelement[2] + 1;
1109 outelement3i[5] = remappedelement[0] + 1;
1118 for (i = 0;i < numshadowmarktris;i++)
1120 int remappedelement[3];
1122 const int *neighbortriangle;
1124 markindex = shadowmarktris[i] * 3;
1125 element = inelement3i + markindex;
1126 neighbortriangle = inneighbor3i + markindex;
1127 // output the front and back triangles
1128 outelement3i[0] = vertexremap[element[2]];
1129 outelement3i[1] = vertexremap[element[1]];
1130 outelement3i[2] = vertexremap[element[0]];
1131 outelement3i[3] = vertexremap[element[0]] + 1;
1132 outelement3i[4] = vertexremap[element[1]] + 1;
1133 outelement3i[5] = vertexremap[element[2]] + 1;
1137 // output the sides (facing outward from this triangle)
1138 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1140 remappedelement[0] = vertexremap[element[0]];
1141 remappedelement[1] = vertexremap[element[1]];
1142 outelement3i[0] = remappedelement[0];
1143 outelement3i[1] = remappedelement[1];
1144 outelement3i[2] = remappedelement[1] + 1;
1145 outelement3i[3] = remappedelement[0];
1146 outelement3i[4] = remappedelement[1] + 1;
1147 outelement3i[5] = remappedelement[0] + 1;
1152 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1154 remappedelement[1] = vertexremap[element[1]];
1155 remappedelement[2] = vertexremap[element[2]];
1156 outelement3i[0] = remappedelement[1];
1157 outelement3i[1] = remappedelement[2];
1158 outelement3i[2] = remappedelement[2] + 1;
1159 outelement3i[3] = remappedelement[1];
1160 outelement3i[4] = remappedelement[2] + 1;
1161 outelement3i[5] = remappedelement[1] + 1;
1166 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1168 remappedelement[0] = vertexremap[element[0]];
1169 remappedelement[2] = vertexremap[element[2]];
1170 outelement3i[0] = remappedelement[2];
1171 outelement3i[1] = remappedelement[0];
1172 outelement3i[2] = remappedelement[0] + 1;
1173 outelement3i[3] = remappedelement[2];
1174 outelement3i[4] = remappedelement[0] + 1;
1175 outelement3i[5] = remappedelement[2] + 1;
1183 *outnumvertices = outvertices;
1184 return outtriangles;
1187 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)
1190 int outtriangles = 0, outvertices = 0;
1192 const float *vertex;
1193 float ratio, direction[3], projectvector[3];
1196 if (projectdirection)
1197 VectorScale(projectdirection, projectdistance, projectvector);
1199 VectorClear(projectvector);
1201 for (i = 0;i < numshadowmarktris;i++)
1203 int remappedelement[3];
1205 const int *neighbortriangle;
1207 markindex = shadowmarktris[i] * 3;
1208 neighbortriangle = inneighbor3i + markindex;
1209 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1210 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1211 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1212 if (side[0] + side[1] + side[2] == 0)
1216 element = inelement3i + markindex;
1218 // create the vertices
1219 for (j = 0;j < 3;j++)
1221 if (side[j] + side[j+1] == 0)
1224 if (vertexupdate[k] != vertexupdatenum)
1226 vertexupdate[k] = vertexupdatenum;
1227 vertexremap[k] = outvertices;
1228 vertex = invertex3f + k * 3;
1229 VectorCopy(vertex, outvertex3f);
1230 if (projectdirection)
1232 // project one copy of the vertex according to projectvector
1233 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1237 // project one copy of the vertex to the sphere radius of the light
1238 // (FIXME: would projecting it to the light box be better?)
1239 VectorSubtract(vertex, projectorigin, direction);
1240 ratio = projectdistance / VectorLength(direction);
1241 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1248 // output the sides (facing outward from this triangle)
1251 remappedelement[0] = vertexremap[element[0]];
1252 remappedelement[1] = vertexremap[element[1]];
1253 outelement3i[0] = remappedelement[1];
1254 outelement3i[1] = remappedelement[0];
1255 outelement3i[2] = remappedelement[0] + 1;
1256 outelement3i[3] = remappedelement[1];
1257 outelement3i[4] = remappedelement[0] + 1;
1258 outelement3i[5] = remappedelement[1] + 1;
1265 remappedelement[1] = vertexremap[element[1]];
1266 remappedelement[2] = vertexremap[element[2]];
1267 outelement3i[0] = remappedelement[2];
1268 outelement3i[1] = remappedelement[1];
1269 outelement3i[2] = remappedelement[1] + 1;
1270 outelement3i[3] = remappedelement[2];
1271 outelement3i[4] = remappedelement[1] + 1;
1272 outelement3i[5] = remappedelement[2] + 1;
1279 remappedelement[0] = vertexremap[element[0]];
1280 remappedelement[2] = vertexremap[element[2]];
1281 outelement3i[0] = remappedelement[0];
1282 outelement3i[1] = remappedelement[2];
1283 outelement3i[2] = remappedelement[2] + 1;
1284 outelement3i[3] = remappedelement[0];
1285 outelement3i[4] = remappedelement[2] + 1;
1286 outelement3i[5] = remappedelement[0] + 1;
1293 *outnumvertices = outvertices;
1294 return outtriangles;
1297 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)
1303 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1305 tend = firsttriangle + numtris;
1306 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1308 // surface box entirely inside light box, no box cull
1309 if (projectdirection)
1311 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1313 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1314 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1315 shadowmarklist[numshadowmark++] = t;
1320 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1321 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1322 shadowmarklist[numshadowmark++] = t;
1327 // surface box not entirely inside light box, cull each triangle
1328 if (projectdirection)
1330 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1332 v[0] = invertex3f + e[0] * 3;
1333 v[1] = invertex3f + e[1] * 3;
1334 v[2] = invertex3f + e[2] * 3;
1335 TriangleNormal(v[0], v[1], v[2], normal);
1336 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1337 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1338 shadowmarklist[numshadowmark++] = t;
1343 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1345 v[0] = invertex3f + e[0] * 3;
1346 v[1] = invertex3f + e[1] * 3;
1347 v[2] = invertex3f + e[2] * 3;
1348 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1349 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1350 shadowmarklist[numshadowmark++] = t;
1356 static qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1361 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1363 // check if the shadow volume intersects the near plane
1365 // a ray between the eye and light origin may intersect the caster,
1366 // indicating that the shadow may touch the eye location, however we must
1367 // test the near plane (a polygon), not merely the eye location, so it is
1368 // easiest to enlarge the caster bounding shape slightly for this.
1374 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)
1376 int i, tris, outverts;
1377 if (projectdistance < 0.1)
1379 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1382 if (!numverts || !nummarktris)
1384 // make sure shadowelements is big enough for this volume
1385 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1386 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1388 if (maxvertexupdate < numverts)
1390 maxvertexupdate = numverts;
1392 Mem_Free(vertexupdate);
1394 Mem_Free(vertexremap);
1395 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1396 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1397 vertexupdatenum = 0;
1400 if (vertexupdatenum == 0)
1402 vertexupdatenum = 1;
1403 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1404 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1407 for (i = 0;i < nummarktris;i++)
1408 shadowmark[marktris[i]] = shadowmarkcount;
1410 if (r_shadow_compilingrtlight)
1412 // if we're compiling an rtlight, capture the mesh
1413 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1414 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1415 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1416 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1418 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1420 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1421 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1422 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1426 // decide which type of shadow to generate and set stencil mode
1427 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1428 // generate the sides or a solid volume, depending on type
1429 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1430 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1432 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1433 r_refdef.stats[r_stat_lights_dynamicshadowtriangles] += tris;
1434 r_refdef.stats[r_stat_lights_shadowtriangles] += tris;
1435 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1437 // increment stencil if frontface is infront of depthbuffer
1438 GL_CullFace(r_refdef.view.cullface_front);
1439 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1440 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1441 // decrement stencil if backface is infront of depthbuffer
1442 GL_CullFace(r_refdef.view.cullface_back);
1443 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1445 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1447 // decrement stencil if backface is behind depthbuffer
1448 GL_CullFace(r_refdef.view.cullface_front);
1449 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1450 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1451 // increment stencil if frontface is behind depthbuffer
1452 GL_CullFace(r_refdef.view.cullface_back);
1453 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1455 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1456 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1460 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1462 // p1, p2, p3 are in the cubemap's local coordinate system
1463 // bias = border/(size - border)
1466 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1467 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1468 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1469 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1471 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1472 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1473 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1474 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1476 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1477 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1478 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1480 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1481 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1482 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1483 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1485 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1486 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1487 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1488 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1490 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1491 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1492 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1494 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1495 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1496 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1497 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1499 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1500 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1501 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1502 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1504 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1505 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1506 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1511 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1513 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1514 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1517 VectorSubtract(maxs, mins, radius);
1518 VectorScale(radius, 0.5f, radius);
1519 VectorAdd(mins, radius, center);
1520 Matrix4x4_Transform(worldtolight, center, lightcenter);
1521 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1522 VectorSubtract(lightcenter, lightradius, pmin);
1523 VectorAdd(lightcenter, lightradius, pmax);
1525 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1526 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1527 if(ap1 > bias*an1 && ap2 > bias*an2)
1529 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1530 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1531 if(an1 > bias*ap1 && an2 > bias*ap2)
1533 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1534 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1536 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1537 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1538 if(ap1 > bias*an1 && ap2 > bias*an2)
1540 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1541 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1542 if(an1 > bias*ap1 && an2 > bias*ap2)
1544 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1545 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1547 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1548 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1549 if(ap1 > bias*an1 && ap2 > bias*an2)
1551 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1552 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1553 if(an1 > bias*ap1 && an2 > bias*ap2)
1555 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1556 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1561 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1563 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1565 // p is in the cubemap's local coordinate system
1566 // bias = border/(size - border)
1567 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1568 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1569 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1571 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1572 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1573 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1574 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1575 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1576 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1580 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1584 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1585 float scale = (size - 2*border)/size, len;
1586 float bias = border / (float)(size - border), dp, dn, ap, an;
1587 // check if cone enclosing side would cross frustum plane
1588 scale = 2 / (scale*scale + 2);
1589 Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
1590 for (i = 0;i < 5;i++)
1592 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
1594 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1595 len = scale*VectorLength2(n);
1596 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1597 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1598 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1600 if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1602 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1603 len = scale*VectorLength2(n);
1604 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1605 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1606 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1608 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1609 // check if frustum corners/origin cross plane sides
1611 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1612 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1613 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1614 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1615 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1616 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1617 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1618 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1619 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1620 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1621 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1622 for (i = 0;i < 4;i++)
1624 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1625 VectorSubtract(n, p, n);
1626 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1627 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1628 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1629 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1630 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1631 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1632 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1633 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1634 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1637 // finite version, assumes corners are a finite distance from origin dependent on far plane
1638 for (i = 0;i < 5;i++)
1640 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1641 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1642 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1643 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1644 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1645 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1646 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1647 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1648 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1649 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1652 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1655 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)
1663 int mask, surfacemask = 0;
1664 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1666 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1667 tend = firsttriangle + numtris;
1668 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1670 // surface box entirely inside light box, no box cull
1671 if (projectdirection)
1673 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1675 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1676 TriangleNormal(v[0], v[1], v[2], normal);
1677 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1679 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1680 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1681 surfacemask |= mask;
1684 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;
1685 shadowsides[numshadowsides] = mask;
1686 shadowsideslist[numshadowsides++] = t;
1693 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1695 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1696 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
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;
1713 // surface box not entirely inside light box, cull each triangle
1714 if (projectdirection)
1716 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1718 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1719 TriangleNormal(v[0], v[1], v[2], normal);
1720 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1721 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1723 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1724 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1725 surfacemask |= mask;
1728 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;
1729 shadowsides[numshadowsides] = mask;
1730 shadowsideslist[numshadowsides++] = t;
1737 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1739 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1740 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1741 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1743 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1744 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1745 surfacemask |= mask;
1748 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;
1749 shadowsides[numshadowsides] = mask;
1750 shadowsideslist[numshadowsides++] = t;
1759 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)
1761 int i, j, outtriangles = 0;
1762 int *outelement3i[6];
1763 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1765 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1766 // make sure shadowelements is big enough for this mesh
1767 if (maxshadowtriangles < outtriangles)
1768 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1770 // compute the offset and size of the separate index lists for each cubemap side
1772 for (i = 0;i < 6;i++)
1774 outelement3i[i] = shadowelements + outtriangles * 3;
1775 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1776 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1777 outtriangles += sidetotals[i];
1780 // gather up the (sparse) triangles into separate index lists for each cubemap side
1781 for (i = 0;i < numsidetris;i++)
1783 const int *element = elements + sidetris[i] * 3;
1784 for (j = 0;j < 6;j++)
1786 if (sides[i] & (1 << j))
1788 outelement3i[j][0] = element[0];
1789 outelement3i[j][1] = element[1];
1790 outelement3i[j][2] = element[2];
1791 outelement3i[j] += 3;
1796 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1799 static void R_Shadow_MakeTextures_MakeCorona(void)
1803 unsigned char pixels[32][32][4];
1804 for (y = 0;y < 32;y++)
1806 dy = (y - 15.5f) * (1.0f / 16.0f);
1807 for (x = 0;x < 32;x++)
1809 dx = (x - 15.5f) * (1.0f / 16.0f);
1810 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1811 a = bound(0, a, 255);
1812 pixels[y][x][0] = a;
1813 pixels[y][x][1] = a;
1814 pixels[y][x][2] = a;
1815 pixels[y][x][3] = 255;
1818 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, false);
1821 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1823 float dist = sqrt(x*x+y*y+z*z);
1824 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1825 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1826 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1829 static void R_Shadow_MakeTextures(void)
1832 float intensity, dist;
1834 R_Shadow_FreeShadowMaps();
1835 R_FreeTexturePool(&r_shadow_texturepool);
1836 r_shadow_texturepool = R_AllocTexturePool();
1837 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1838 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1839 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1840 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1841 for (x = 0;x <= ATTENTABLESIZE;x++)
1843 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1844 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1845 r_shadow_attentable[x] = bound(0, intensity, 1);
1847 // 1D gradient texture
1848 for (x = 0;x < ATTEN1DSIZE;x++)
1849 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1850 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1851 // 2D circle texture
1852 for (y = 0;y < ATTEN2DSIZE;y++)
1853 for (x = 0;x < ATTEN2DSIZE;x++)
1854 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);
1855 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1856 // 3D sphere texture
1857 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1859 for (z = 0;z < ATTEN3DSIZE;z++)
1860 for (y = 0;y < ATTEN3DSIZE;y++)
1861 for (x = 0;x < ATTEN3DSIZE;x++)
1862 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));
1863 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);
1866 r_shadow_attenuation3dtexture = NULL;
1869 R_Shadow_MakeTextures_MakeCorona();
1871 // Editor light sprites
1872 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1889 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1890 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1907 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1908 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1925 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1926 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1943 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1944 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1961 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1962 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1979 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1982 void R_Shadow_ValidateCvars(void)
1984 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1985 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1986 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1987 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1988 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1989 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1992 void R_Shadow_RenderMode_Begin(void)
1998 R_Shadow_ValidateCvars();
2000 if (!r_shadow_attenuation2dtexture
2001 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
2002 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
2003 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
2004 R_Shadow_MakeTextures();
2007 R_Mesh_ResetTextureState();
2008 GL_BlendFunc(GL_ONE, GL_ZERO);
2009 GL_DepthRange(0, 1);
2010 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
2012 GL_DepthMask(false);
2013 GL_Color(0, 0, 0, 1);
2014 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2016 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2018 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
2020 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
2021 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
2023 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
2025 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
2026 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
2030 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
2031 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
2034 switch(vid.renderpath)
2036 case RENDERPATH_GL20:
2037 case RENDERPATH_D3D9:
2038 case RENDERPATH_D3D10:
2039 case RENDERPATH_D3D11:
2040 case RENDERPATH_SOFT:
2041 case RENDERPATH_GLES2:
2042 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
2044 case RENDERPATH_GL11:
2045 case RENDERPATH_GL13:
2046 case RENDERPATH_GLES1:
2047 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
2048 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
2049 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
2050 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
2051 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
2052 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
2054 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
2060 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
2061 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
2062 r_shadow_drawbuffer = drawbuffer;
2063 r_shadow_readbuffer = readbuffer;
2065 r_shadow_cullface_front = r_refdef.view.cullface_front;
2066 r_shadow_cullface_back = r_refdef.view.cullface_back;
2069 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
2071 rsurface.rtlight = rtlight;
2074 void R_Shadow_RenderMode_Reset(void)
2076 R_Mesh_ResetTextureState();
2077 R_Mesh_SetRenderTargets(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture, NULL, NULL, NULL);
2078 R_SetViewport(&r_refdef.view.viewport);
2079 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
2080 GL_DepthRange(0, 1);
2082 GL_DepthMask(false);
2083 GL_DepthFunc(GL_LEQUAL);
2084 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2085 r_refdef.view.cullface_front = r_shadow_cullface_front;
2086 r_refdef.view.cullface_back = r_shadow_cullface_back;
2087 GL_CullFace(r_refdef.view.cullface_back);
2088 GL_Color(1, 1, 1, 1);
2089 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2090 GL_BlendFunc(GL_ONE, GL_ZERO);
2091 R_SetupShader_Generic_NoTexture(false, false);
2092 r_shadow_usingshadowmap2d = false;
2093 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2096 void R_Shadow_ClearStencil(void)
2098 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2099 r_refdef.stats[r_stat_lights_clears]++;
2102 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2104 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2105 if (r_shadow_rendermode == mode)
2107 R_Shadow_RenderMode_Reset();
2108 GL_DepthFunc(GL_LESS);
2109 GL_ColorMask(0, 0, 0, 0);
2110 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2111 GL_CullFace(GL_NONE);
2112 R_SetupShader_DepthOrShadow(false, false, false); // FIXME test if we have a skeletal model?
2113 r_shadow_rendermode = mode;
2118 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2119 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2120 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2122 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2123 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2124 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2129 static void R_Shadow_MakeVSDCT(void)
2131 // maps to a 2x3 texture rectangle with normalized coordinates
2136 // stores abs(dir.xy), offset.xy/2.5
2137 unsigned char data[4*6] =
2139 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2140 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2141 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2142 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2143 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2144 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2146 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2149 static void R_Shadow_MakeShadowMap(int texturesize)
2151 switch (r_shadow_shadowmode)
2153 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2154 if (r_shadow_shadowmap2ddepthtexture) return;
2155 if (r_fb.usedepthtextures)
2157 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);
2158 r_shadow_shadowmap2ddepthbuffer = NULL;
2159 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2163 r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", texturesize, texturesize, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2164 r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
2165 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2173 void R_Shadow_ClearShadowMapTexture(void)
2175 r_viewport_t viewport;
2176 float clearcolor[4];
2178 // if they don't exist, create our textures now
2179 if (!r_shadow_shadowmap2ddepthtexture)
2180 R_Shadow_MakeShadowMap(r_shadow_shadowmaptexturesize);
2181 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2182 R_Shadow_MakeVSDCT();
2184 // we're setting up to render shadowmaps, so change rendermode
2185 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2187 R_Mesh_ResetTextureState();
2188 R_Shadow_RenderMode_Reset();
2189 if (r_shadow_shadowmap2ddepthbuffer)
2190 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2192 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2193 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2194 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2198 // we have to set a viewport to clear anything in some renderpaths (D3D)
2199 R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize, 0, 0, 1.0, 1.0, 0.001f, 1.0f, NULL);
2200 R_SetViewport(&viewport);
2201 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2202 if (r_shadow_shadowmap2ddepthbuffer)
2203 GL_ColorMask(1, 1, 1, 1);
2205 GL_ColorMask(0, 0, 0, 0);
2206 switch (vid.renderpath)
2208 case RENDERPATH_GL11:
2209 case RENDERPATH_GL13:
2210 case RENDERPATH_GL20:
2211 case RENDERPATH_SOFT:
2212 case RENDERPATH_GLES1:
2213 case RENDERPATH_GLES2:
2214 GL_CullFace(r_refdef.view.cullface_back);
2216 case RENDERPATH_D3D9:
2217 case RENDERPATH_D3D10:
2218 case RENDERPATH_D3D11:
2219 // we invert the cull mode because we flip the projection matrix
2220 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2221 GL_CullFace(r_refdef.view.cullface_front);
2224 Vector4Set(clearcolor, 1, 1, 1, 1);
2225 if (r_shadow_shadowmap2ddepthbuffer)
2226 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2228 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2231 static void R_Shadow_SetShadowmapParametersForLight(qboolean noselfshadowpass)
2233 int size = rsurface.rtlight->shadowmapatlassidesize;
2234 float nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2235 float farclip = 1.0f;
2236 float bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2237 r_shadow_lightshadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
2238 r_shadow_lightshadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
2239 r_shadow_lightshadowmap_texturescale[2] = rsurface.rtlight->shadowmapatlasposition[0] + (noselfshadowpass ? size * 2 : 0);
2240 r_shadow_lightshadowmap_texturescale[3] = rsurface.rtlight->shadowmapatlasposition[1];
2241 r_shadow_lightshadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2242 r_shadow_lightshadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2243 r_shadow_lightshadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2244 r_shadow_lightshadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2245 if (r_shadow_shadowmap2ddepthbuffer)
2247 // completely different meaning than in depthtexture approach
2248 r_shadow_lightshadowmap_parameters[1] = 0;
2249 r_shadow_lightshadowmap_parameters[3] = -bias;
2253 static void R_Shadow_RenderMode_ShadowMap(int side, int size, int x, int y)
2255 float nearclip, farclip, bias;
2256 r_viewport_t viewport;
2258 float clearcolor[4];
2260 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_SHADOWMAP2D)
2262 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2264 R_Mesh_ResetTextureState();
2265 R_Shadow_RenderMode_Reset();
2266 if (r_shadow_shadowmap2ddepthbuffer)
2267 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2269 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2270 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2271 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2276 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2278 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2280 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
2281 R_SetViewport(&viewport);
2282 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2283 flipped = (side & 1) ^ (side >> 2);
2284 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2285 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2287 Vector4Set(clearcolor, 1,1,1,1);
2288 if (r_shadow_shadowmap2ddepthbuffer)
2289 GL_ColorMask(1,1,1,1);
2291 GL_ColorMask(0,0,0,0);
2292 switch(vid.renderpath)
2294 case RENDERPATH_GL11:
2295 case RENDERPATH_GL13:
2296 case RENDERPATH_GL20:
2297 case RENDERPATH_SOFT:
2298 case RENDERPATH_GLES1:
2299 case RENDERPATH_GLES2:
2300 GL_CullFace(r_refdef.view.cullface_back);
2302 case RENDERPATH_D3D9:
2303 case RENDERPATH_D3D10:
2304 case RENDERPATH_D3D11:
2305 // we invert the cull mode because we flip the projection matrix
2306 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2307 GL_CullFace(r_refdef.view.cullface_front);
2311 // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
2312 r_shadow_shadowmapside = side;
2315 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass)
2317 R_Mesh_ResetTextureState();
2320 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2321 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2322 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2323 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2326 R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
2327 R_Shadow_RenderMode_Reset();
2328 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2330 GL_DepthFunc(GL_EQUAL);
2331 // do global setup needed for the chosen lighting mode
2332 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2333 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2334 r_shadow_usingshadowmap2d = shadowmapping;
2335 r_shadow_rendermode = r_shadow_lightingrendermode;
2336 // only draw light where this geometry was already rendered AND the
2337 // stencil is 128 (values other than this mean shadow)
2339 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2341 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2344 static const unsigned short bboxelements[36] =
2354 static const float bboxpoints[8][3] =
2366 void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping)
2369 float vertex3f[8*3];
2370 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2371 // do global setup needed for the chosen lighting mode
2372 R_Shadow_RenderMode_Reset();
2373 r_shadow_rendermode = r_shadow_lightingrendermode;
2374 R_EntityMatrix(&identitymatrix);
2375 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2376 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2377 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
2378 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2380 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
2382 r_shadow_usingshadowmap2d = shadowmapping;
2384 // render the lighting
2385 R_SetupShader_DeferredLight(rsurface.rtlight);
2386 for (i = 0;i < 8;i++)
2387 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2388 GL_ColorMask(1,1,1,1);
2389 GL_DepthMask(false);
2390 GL_DepthRange(0, 1);
2391 GL_PolygonOffset(0, 0);
2393 GL_DepthFunc(GL_GREATER);
2394 GL_CullFace(r_refdef.view.cullface_back);
2395 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
2396 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2399 #define MAXBOUNCEGRIDSPLATSIZE 7
2400 #define MAXBOUNCEGRIDSPLATSIZE1 (MAXBOUNCEGRIDSPLATSIZE+1)
2402 // these are temporary data per-frame, sorted and performed in a more
2403 // cache-friendly order than the original photons
2404 typedef struct r_shadow_bouncegrid_splatpath_s
2410 vec_t splatintensity;
2411 int remainingsplats;
2413 r_shadow_bouncegrid_splatpath_t;
2415 static void R_Shadow_BounceGrid_AddSplatPath(vec3_t originalstart, vec3_t originalend, vec3_t color)
2425 r_shadow_bouncegrid_splatpath_t *path;
2427 // cull paths that fail R_CullBox in dynamic mode
2428 if (!r_shadow_bouncegrid_state.settings.staticmode
2429 && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
2431 vec3_t cullmins, cullmaxs;
2432 cullmins[0] = min(originalstart[0], originalend[0]) - r_shadow_bouncegrid_state.settings.spacing[0];
2433 cullmins[1] = min(originalstart[1], originalend[1]) - r_shadow_bouncegrid_state.settings.spacing[1];
2434 cullmins[2] = min(originalstart[2], originalend[2]) - r_shadow_bouncegrid_state.settings.spacing[2];
2435 cullmaxs[0] = max(originalstart[0], originalend[0]) + r_shadow_bouncegrid_state.settings.spacing[0];
2436 cullmaxs[1] = max(originalstart[1], originalend[1]) + r_shadow_bouncegrid_state.settings.spacing[1];
2437 cullmaxs[2] = max(originalstart[2], originalend[2]) + r_shadow_bouncegrid_state.settings.spacing[2];
2438 if (R_CullBox(cullmins, cullmaxs))
2442 // if the light path is going upward, reverse it - we always draw down.
2443 if (originalend[2] < originalstart[2])
2445 VectorCopy(originalend, start);
2446 VectorCopy(originalstart, end);
2450 VectorCopy(originalstart, start);
2451 VectorCopy(originalend, end);
2454 // transform to texture pixels
2455 start[0] = (start[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2456 start[1] = (start[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2457 start[2] = (start[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2458 end[0] = (end[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2459 end[1] = (end[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2460 end[2] = (end[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2462 // check if we need to grow the splatpaths array
2463 if (r_shadow_bouncegrid_state.maxsplatpaths <= r_shadow_bouncegrid_state.numsplatpaths)
2465 // double the limit, this will persist from frame to frame so we don't
2466 // make the same mistake each time
2467 r_shadow_bouncegrid_splatpath_t *newpaths;
2468 r_shadow_bouncegrid_state.maxsplatpaths *= 2;
2469 newpaths = (r_shadow_bouncegrid_splatpath_t *)R_FrameData_Alloc(sizeof(r_shadow_bouncegrid_splatpath_t) * r_shadow_bouncegrid_state.maxsplatpaths);
2470 if (r_shadow_bouncegrid_state.splatpaths)
2471 memcpy(newpaths, r_shadow_bouncegrid_state.splatpaths, r_shadow_bouncegrid_state.numsplatpaths * sizeof(r_shadow_bouncegrid_splatpath_t));
2472 r_shadow_bouncegrid_state.splatpaths = newpaths;
2475 // divide a series of splats along the length using the maximum axis
2476 VectorSubtract(end, start, diff);
2477 // pick the best axis to trace along
2479 if (diff[1]*diff[1] > diff[bestaxis]*diff[bestaxis])
2481 if (diff[2]*diff[2] > diff[bestaxis]*diff[bestaxis])
2483 len = fabs(diff[bestaxis]);
2485 numsplats = (int)(floor(len + 0.5f));
2487 numsplats = bound(0, numsplats, 1024);
2489 VectorSubtract(originalstart, originalend, originaldir);
2490 VectorNormalize(originaldir);
2492 path = r_shadow_bouncegrid_state.splatpaths + r_shadow_bouncegrid_state.numsplatpaths++;
2493 VectorCopy(start, path->point);
2494 VectorScale(diff, ilen, path->step);
2495 VectorCopy(color, path->splatcolor);
2496 VectorCopy(originaldir, path->splatdir);
2497 path->splatintensity = VectorLength(color);
2498 path->remainingsplats = numsplats;
2501 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
2503 qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
2510 // see if there are really any lights to render...
2511 if (enable && r_shadow_bouncegrid_static.integer)
2514 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2515 for (lightindex = 0;lightindex < range;lightindex++)
2517 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2518 if (!light || !(light->flags & flag))
2520 rtlight = &light->rtlight;
2521 // when static, we skip styled lights because they tend to change...
2522 if (rtlight->style > 0)
2524 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
2525 if (!VectorLength2(lightcolor))
2535 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
2537 qboolean s = r_shadow_bouncegrid_static.integer != 0;
2538 float spacing = s ? r_shadow_bouncegrid_static_spacing.value : r_shadow_bouncegrid_dynamic_spacing.value;
2540 // prevent any garbage in alignment padded areas as we'll be using memcmp
2541 memset(settings, 0, sizeof(*settings));
2543 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
2544 settings->staticmode = s;
2545 settings->blur = r_shadow_bouncegrid_blur.integer != 0;
2546 settings->floatcolors = bound(0, r_shadow_bouncegrid_floatcolors.integer, 2);
2547 settings->lightpathsize = bound(1, r_shadow_bouncegrid_lightpathsize.integer, MAXBOUNCEGRIDSPLATSIZE);
2548 settings->bounceanglediffuse = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
2549 settings->directionalshading = (s ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_dynamic_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
2550 settings->dlightparticlemultiplier = s ? 0 : r_shadow_bouncegrid_dynamic_dlightparticlemultiplier.value;
2551 settings->hitmodels = s ? false : r_shadow_bouncegrid_dynamic_hitmodels.integer != 0;
2552 settings->includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
2553 settings->lightradiusscale = (s ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_dynamic_lightradiusscale.value);
2554 settings->maxbounce = (s ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_dynamic_maxbounce.integer);
2555 settings->particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
2556 settings->particleintensity = r_shadow_bouncegrid_particleintensity.value * 16384.0f * (settings->directionalshading ? 4.0f : 1.0f) / (spacing * spacing);
2557 settings->maxphotons = s ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_dynamic_maxphotons.integer;
2558 settings->energyperphoton = s ? r_shadow_bouncegrid_static_energyperphoton.integer : r_shadow_bouncegrid_dynamic_energyperphoton.integer;
2559 settings->spacing[0] = spacing;
2560 settings->spacing[1] = spacing;
2561 settings->spacing[2] = spacing;
2562 settings->stablerandom = s ? 1 : r_shadow_bouncegrid_dynamic_stablerandom.integer;
2564 // bound the values for sanity
2565 settings->maxphotons = bound(1, settings->maxphotons, 25000000);
2566 settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
2567 settings->maxbounce = bound(0, settings->maxbounce, 16);
2568 settings->spacing[0] = bound(1, settings->spacing[0], 512);
2569 settings->spacing[1] = bound(1, settings->spacing[1], 512);
2570 settings->spacing[2] = bound(1, settings->spacing[2], 512);
2573 static void R_Shadow_BounceGrid_UpdateSpacing(void)
2584 r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
2586 // get the spacing values
2587 spacing[0] = settings->spacing[0];
2588 spacing[1] = settings->spacing[1];
2589 spacing[2] = settings->spacing[2];
2590 ispacing[0] = 1.0f / spacing[0];
2591 ispacing[1] = 1.0f / spacing[1];
2592 ispacing[2] = 1.0f / spacing[2];
2594 // calculate texture size enclosing entire world bounds at the spacing
2595 if (r_refdef.scene.worldmodel)
2597 VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
2598 VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
2602 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
2603 VectorSet(maxs, 1048576.0f, 1048576.0f, 1048576.0f);
2605 VectorSubtract(maxs, mins, size);
2606 // now we can calculate the resolution we want
2607 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2608 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2609 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2610 // figure out the exact texture size (honoring power of 2 if required)
2611 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2612 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2613 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2614 if (vid.support.arb_texture_non_power_of_two)
2616 resolution[0] = c[0];
2617 resolution[1] = c[1];
2618 resolution[2] = c[2];
2622 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2623 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2624 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2626 size[0] = spacing[0] * resolution[0];
2627 size[1] = spacing[1] * resolution[1];
2628 size[2] = spacing[2] * resolution[2];
2630 // if dynamic we may or may not want to use the world bounds
2631 // if the dynamic size is smaller than the world bounds, use it instead
2632 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]))
2634 // we know the resolution we want
2635 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
2636 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
2637 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
2638 // now we can calculate the texture size (power of 2 if required)
2639 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2640 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2641 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2642 if (vid.support.arb_texture_non_power_of_two)
2644 resolution[0] = c[0];
2645 resolution[1] = c[1];
2646 resolution[2] = c[2];
2650 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2651 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2652 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2654 size[0] = spacing[0] * resolution[0];
2655 size[1] = spacing[1] * resolution[1];
2656 size[2] = spacing[2] * resolution[2];
2657 // center the rendering on the view
2658 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2659 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2660 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2663 // recalculate the maxs in case the resolution was not satisfactory
2664 VectorAdd(mins, size, maxs);
2666 // check if this changed the texture size
2667 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);
2668 r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
2669 VectorCopy(mins, r_shadow_bouncegrid_state.mins);
2670 VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
2671 VectorCopy(size, r_shadow_bouncegrid_state.size);
2672 VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
2673 VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
2674 VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
2676 // reallocate pixels for this update if needed...
2677 r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
2678 r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
2679 r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
2680 numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
2681 if (r_shadow_bouncegrid_state.numpixels != numpixels)
2683 if (r_shadow_bouncegrid_state.texture)
2685 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2686 r_shadow_bouncegrid_state.texture = NULL;
2688 r_shadow_bouncegrid_state.numpixels = numpixels;
2691 // update the bouncegrid matrix to put it in the world properly
2692 memset(m, 0, sizeof(m));
2693 m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
2694 m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
2695 m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
2696 m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
2697 m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
2698 m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
2700 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
2703 #define MAXBOUNCEGRIDPARTICLESPERLIGHT 1048576
2705 // enumerate world rtlights and sum the overall amount of light in the world,
2706 // from that we can calculate a scaling factor to fairly distribute photons
2707 // to all the lights
2709 // this modifies rtlight->photoncolor and rtlight->photons
2710 static void R_Shadow_BounceGrid_AssignPhotons(r_shadow_bouncegrid_settings_t *settings, unsigned int range, unsigned int range1, unsigned int range2, int flag, float *photonscaling)
2712 float normalphotonscaling;
2713 float maxphotonscaling;
2714 float photoncount = 0.0f;
2715 float lightintensity;
2721 unsigned int lightindex;
2724 for (lightindex = 0;lightindex < range2;lightindex++)
2726 if (lightindex < range)
2728 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2731 rtlight = &light->rtlight;
2732 VectorClear(rtlight->photoncolor);
2733 rtlight->photons = 0;
2734 if (!(light->flags & flag))
2736 if (settings->staticmode)
2738 // when static, we skip styled lights because they tend to change...
2739 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2745 rtlight = r_refdef.scene.lights[lightindex - range];
2746 VectorClear(rtlight->photoncolor);
2747 rtlight->photons = 0;
2749 // draw only visible lights (major speedup)
2750 radius = rtlight->radius * settings->lightradiusscale;
2751 cullmins[0] = rtlight->shadoworigin[0] - radius;
2752 cullmins[1] = rtlight->shadoworigin[1] - radius;
2753 cullmins[2] = rtlight->shadoworigin[2] - radius;
2754 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2755 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2756 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2757 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2758 if (!settings->staticmode)
2760 if (R_CullBox(cullmins, cullmaxs))
2762 if (r_refdef.scene.worldmodel
2763 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2764 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2766 if (w * VectorLength2(rtlight->color) == 0.0f)
2769 // a light that does not emit any light before style is applied, can be
2770 // skipped entirely (it may just be a corona)
2771 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2773 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2774 VectorScale(rtlight->color, w, rtlight->photoncolor);
2775 // skip lights that will emit no photons
2776 if (!VectorLength2(rtlight->photoncolor))
2778 // shoot particles from this light
2779 // use a calculation for the number of particles that will not
2780 // vary with lightstyle, otherwise we get randomized particle
2781 // distribution, the seeded random is only consistent for a
2782 // consistent number of particles on this light...
2783 s = rtlight->radius;
2784 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2785 if (lightindex >= range)
2786 lightintensity *= settings->dlightparticlemultiplier;
2787 rtlight->photons = bound(0.0f, lightintensity * s * s, MAXBOUNCEGRIDPARTICLESPERLIGHT);
2788 photoncount += rtlight->photons;
2789 // if the lightstyle happens to be off right now, we can skip actually
2790 // firing the photons, but we did have to count them in the total.
2791 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2792 // rtlight->photons = 0;
2794 // the user provided an energyperphoton value which we try to use
2795 // if that results in too many photons to shoot this frame, then we cap it
2796 // which causes photons to appear/disappear from frame to frame, so we don't
2797 // like doing that in the typical case
2798 normalphotonscaling = 1.0f / max(0.0001f, settings->energyperphoton);
2799 maxphotonscaling = (float)settings->maxphotons / max(1, photoncount);
2800 *photonscaling = min(normalphotonscaling, maxphotonscaling);
2803 static int R_Shadow_BounceGrid_SplatPathCompare(const void *pa, const void *pb)
2805 r_shadow_bouncegrid_splatpath_t *a = (r_shadow_bouncegrid_splatpath_t *)pa;
2806 r_shadow_bouncegrid_splatpath_t *b = (r_shadow_bouncegrid_splatpath_t *)pb;
2807 // we only really care about sorting by Z
2808 if (a->point[2] < b->point[2])
2810 if (a->point[2] > b->point[2])
2815 static void R_Shadow_BounceGrid_ClearPixels(void)
2817 // clear the highpixels array we'll be accumulating into
2818 r_shadow_bouncegrid_state.highpixels = (float *)R_FrameData_Alloc(r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2819 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2822 static void R_Shadow_BounceGrid_PerformSplats(void)
2824 int splatsize = r_shadow_bouncegrid_state.settings.lightpathsize;
2825 int splatsize1 = splatsize + 1;
2826 r_shadow_bouncegrid_splatpath_t *splatpaths = r_shadow_bouncegrid_state.splatpaths;
2827 r_shadow_bouncegrid_splatpath_t *splatpath;
2828 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2829 int numsplatpaths = r_shadow_bouncegrid_state.numsplatpaths;
2835 float texlerp[MAXBOUNCEGRIDSPLATSIZE1][3];
2836 float splatcolor[32];
2837 float boxweight = 1.0f / (splatsize * splatsize * splatsize);
2840 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2841 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2845 // hush warnings about uninitialized data - pixelbands doesn't change but...
2846 memset(splatcolor, 0, sizeof(splatcolor));
2848 // we use this a lot, so get a local copy
2849 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2851 // sort the splats before we execute them, to reduce cache misses
2852 if (r_shadow_bouncegrid_sortlightpaths.integer)
2853 qsort(splatpaths, numsplatpaths, sizeof(*splatpaths), R_Shadow_BounceGrid_SplatPathCompare);
2855 // the middle row/column/layer of each splat are full intensity
2856 for (step = 1;step < splatsize;step++)
2857 VectorSet(texlerp[step], 1.0f, 1.0f, 1.0f);
2859 splatpath = splatpaths;
2860 for (splatindex = 0;splatindex < numsplatpaths;splatindex++, splatpath++)
2862 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2863 // accumulate average shotcolor
2864 VectorCopy(splatpath->splatdir, dir);
2865 splatcolor[ 0] = splatpath->splatcolor[0];
2866 splatcolor[ 1] = splatpath->splatcolor[1];
2867 splatcolor[ 2] = splatpath->splatcolor[2];
2868 splatcolor[ 3] = 0.0f;
2871 // store bentnormal in case the shader has a use for it,
2872 // bentnormal is an intensity-weighted average of the directions,
2873 // and will be normalized on conversion to texture pixels.
2874 splatcolor[ 4] = dir[0] * splatpath->splatintensity;
2875 splatcolor[ 5] = dir[1] * splatpath->splatintensity;
2876 splatcolor[ 6] = dir[2] * splatpath->splatintensity;
2877 splatcolor[ 7] = splatpath->splatintensity;
2878 // for each color component (R, G, B) calculate the amount that a
2879 // direction contributes
2880 splatcolor[ 8] = splatcolor[0] * max(0.0f, dir[0]);
2881 splatcolor[ 9] = splatcolor[0] * max(0.0f, dir[1]);
2882 splatcolor[10] = splatcolor[0] * max(0.0f, dir[2]);
2883 splatcolor[11] = 0.0f;
2884 splatcolor[12] = splatcolor[1] * max(0.0f, dir[0]);
2885 splatcolor[13] = splatcolor[1] * max(0.0f, dir[1]);
2886 splatcolor[14] = splatcolor[1] * max(0.0f, dir[2]);
2887 splatcolor[15] = 0.0f;
2888 splatcolor[16] = splatcolor[2] * max(0.0f, dir[0]);
2889 splatcolor[17] = splatcolor[2] * max(0.0f, dir[1]);
2890 splatcolor[18] = splatcolor[2] * max(0.0f, dir[2]);
2891 splatcolor[19] = 0.0f;
2892 // and do the same for negative directions
2893 splatcolor[20] = splatcolor[0] * max(0.0f, -dir[0]);
2894 splatcolor[21] = splatcolor[0] * max(0.0f, -dir[1]);
2895 splatcolor[22] = splatcolor[0] * max(0.0f, -dir[2]);
2896 splatcolor[23] = 0.0f;
2897 splatcolor[24] = splatcolor[1] * max(0.0f, -dir[0]);
2898 splatcolor[25] = splatcolor[1] * max(0.0f, -dir[1]);
2899 splatcolor[26] = splatcolor[1] * max(0.0f, -dir[2]);
2900 splatcolor[27] = 0.0f;
2901 splatcolor[28] = splatcolor[2] * max(0.0f, -dir[0]);
2902 splatcolor[29] = splatcolor[2] * max(0.0f, -dir[1]);
2903 splatcolor[30] = splatcolor[2] * max(0.0f, -dir[2]);
2904 splatcolor[31] = 0.0f;
2906 // calculate the number of steps we need to traverse this distance
2907 VectorCopy(splatpath->point, steppos);
2908 VectorCopy(splatpath->step, stepdelta);
2909 numsteps = splatpath->remainingsplats;
2910 for (step = 0;step < numsteps;step++)
2912 r_refdef.stats[r_stat_bouncegrid_splats]++;
2913 // figure out the min corner of the pixels we'll need to update
2914 texcorner[0] = steppos[0] - (splatsize1 * 0.5f);
2915 texcorner[1] = steppos[1] - (splatsize1 * 0.5f);
2916 texcorner[2] = steppos[2] - (splatsize1 * 0.5f);
2917 tex[0] = (int)floor(texcorner[0]);
2918 tex[1] = (int)floor(texcorner[1]);
2919 tex[2] = (int)floor(texcorner[2]);
2920 // only update if it is within reasonable bounds
2924 && tex[0] < resolution[0] - splatsize1
2925 && tex[1] < resolution[1] - splatsize1
2926 && tex[2] < resolution[2] - splatsize1)
2928 // it is within bounds... do the real work now
2931 // calculate the antialiased box edges
2932 texlerp[splatsize][0] = texcorner[0] - tex[0];
2933 texlerp[splatsize][1] = texcorner[1] - tex[1];
2934 texlerp[splatsize][2] = texcorner[2] - tex[2];
2935 texlerp[0][0] = 1.0f - texlerp[splatsize][0];
2936 texlerp[0][1] = 1.0f - texlerp[splatsize][1];
2937 texlerp[0][2] = 1.0f - texlerp[splatsize][2];
2939 // accumulate light onto the pixels
2940 for (zi = 0;zi < splatsize1;zi++)
2942 for (yi = 0;yi < splatsize1;yi++)
2944 int index = ((tex[2]+zi)*resolution[1]+tex[1]+yi)*resolution[0]+tex[0];
2945 for (xi = 0;xi < splatsize1;xi++, index++)
2947 float w = texlerp[xi][0]*texlerp[yi][1]*texlerp[zi][2] * boxweight;
2949 float *p = highpixels + 4 * index + band * pixelsperband * 4;
2950 for (;band < pixelbands;band++, p += pixelsperband * 4)
2952 // add to the pixel color
2953 p[0] += splatcolor[band*4+0] * w;
2954 p[1] += splatcolor[band*4+1] * w;
2955 p[2] += splatcolor[band*4+2] * w;
2956 p[3] += splatcolor[band*4+3] * w;
2962 VectorAdd(steppos, stepdelta, steppos);
2967 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
2969 const float *inpixel;
2971 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2974 unsigned int x, y, z;
2975 unsigned int resolution[3];
2976 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2977 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2979 for (z = 1;z < resolution[2]-1;z++)
2981 for (y = 1;y < resolution[1]-1;y++)
2984 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2985 inpixel = inpixels + 4*index;
2986 outpixel = outpixels + 4*index;
2987 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
2989 outpixel[0] = (inpixel[0] + inpixel[ off] + inpixel[0-off]) * (1.0f / 3.0);
2990 outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
2991 outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
2992 outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
2999 static void R_Shadow_BounceGrid_BlurPixels(void)
3001 float *highpixels = r_shadow_bouncegrid_state.highpixels;
3002 float *temppixels1 = (float *)R_FrameData_Alloc(r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
3003 float *temppixels2 = (float *)R_FrameData_Alloc(r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
3004 unsigned int resolution[3];
3006 if (!r_shadow_bouncegrid_blur.integer)
3009 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3012 R_Shadow_BounceGrid_BlurPixelsInDirection(highpixels, temppixels1, 4);
3014 R_Shadow_BounceGrid_BlurPixelsInDirection(temppixels1, temppixels2, resolution[0] * 4);
3016 R_Shadow_BounceGrid_BlurPixelsInDirection(temppixels2, highpixels, resolution[0] * resolution[1] * 4);
3019 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
3021 int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
3022 unsigned char *pixelsbgra8 = NULL;
3023 unsigned char *pixelbgra8;
3024 unsigned short *pixelsrgba16f = NULL;
3025 unsigned short *pixelrgba16f;
3026 float *pixelsrgba32f = NULL;
3027 float *highpixels = r_shadow_bouncegrid_state.highpixels;
3030 unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
3031 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
3032 unsigned int pixelband;
3033 unsigned int x, y, z;
3034 unsigned int index, bandindex;
3035 unsigned int resolution[3];
3037 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3039 if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
3041 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3042 r_shadow_bouncegrid_state.texture = NULL;
3045 // if bentnormals exist, we need to normalize and bias them for the shader
3049 for (z = 0;z < resolution[2]-1;z++)
3051 for (y = 0;y < resolution[1]-1;y++)
3054 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3055 highpixel = highpixels + 4*index;
3056 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3058 // only convert pixels that were hit by photons
3059 if (highpixel[3] != 0.0f)
3060 VectorNormalize(highpixel);
3061 VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
3062 highpixel[pixelsperband * 4 + 3] = 1.0f;
3068 // start by clearing the pixels array - we won't be writing to all of it
3070 // then process only the pixels that have at least some color, skipping
3071 // the higher bands for speed on pixels that are black
3072 switch (floatcolors)
3075 pixelsbgra8 = (unsigned char *)R_FrameData_Alloc(r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
3076 for (pixelband = 0;pixelband < pixelbands;pixelband++)
3079 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
3081 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
3083 for (z = 1;z < resolution[2]-1;z++)
3085 for (y = 1;y < resolution[1]-1;y++)
3089 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3090 highpixel = highpixels + 4*index;
3091 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3093 // only convert pixels that were hit by photons
3094 if (VectorLength2(highpixel))
3096 // normalize the bentnormal now
3099 VectorNormalize(highpixel + pixelsperband * 4);
3100 highpixel[pixelsperband * 4 + 3] = 1.0f;
3102 // process all of the pixelbands for this pixel
3103 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3105 pixelbgra8 = pixelsbgra8 + 4*bandindex;
3106 bandpixel = highpixels + 4*bandindex;
3107 c[0] = (int)(bandpixel[0]*256.0f);
3108 c[1] = (int)(bandpixel[1]*256.0f);
3109 c[2] = (int)(bandpixel[2]*256.0f);
3110 c[3] = (int)(bandpixel[3]*256.0f);
3111 pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
3112 pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
3113 pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
3114 pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
3121 if (!r_shadow_bouncegrid_state.createtexture)
3122 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3124 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);
3127 pixelsrgba16f = (unsigned short *)R_FrameData_Alloc(r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3128 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3129 for (z = 1;z < resolution[2]-1;z++)
3131 for (y = 1;y < resolution[1]-1;y++)
3135 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3136 highpixel = highpixels + 4*index;
3137 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3139 // only convert pixels that were hit by photons
3140 if (VectorLength2(highpixel))
3142 // process all of the pixelbands for this pixel
3143 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3145 // time to have fun with IEEE 754 bit hacking...
3148 unsigned int raw[4];
3150 pixelrgba16f = pixelsrgba16f + 4*bandindex;
3151 bandpixel = highpixels + 4*bandindex;
3152 VectorCopy4(bandpixel, u.f);
3153 VectorCopy4(u.raw, c);
3154 // this math supports negative numbers, snaps denormals to zero
3155 //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
3156 //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
3157 //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
3158 //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
3159 // this math does not support negative
3160 pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
3161 pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
3162 pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
3163 pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
3170 if (!r_shadow_bouncegrid_state.createtexture)
3171 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3173 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);
3176 // our native format happens to match, so this is easy.
3177 pixelsrgba32f = highpixels;
3179 if (!r_shadow_bouncegrid_state.createtexture)
3180 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3182 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);
3186 r_shadow_bouncegrid_state.lastupdatetime = realtime;
3189 static void R_Shadow_BounceGrid_TracePhotons(r_shadow_bouncegrid_settings_t settings, unsigned int range, unsigned int range1, unsigned int range2, float photonscaling, int flag)
3191 vec3_t bouncerandom[10];
3194 int hitsupercontentsmask;
3195 int skipsupercontentsmask;
3200 //trace_t cliptrace2;
3201 //trace_t cliptrace3;
3202 unsigned int lightindex;
3203 unsigned int seed = (unsigned int)(realtime * 1000.0f);
3204 randomseed_t randomseed;
3206 vec3_t baseshotcolor;
3215 Math_RandomSeed_FromInt(&randomseed, seed);
3217 r_shadow_bouncegrid_state.numsplatpaths = 0;
3218 r_shadow_bouncegrid_state.splatpaths = (r_shadow_bouncegrid_splatpath_t *)R_FrameData_Alloc(sizeof(r_shadow_bouncegrid_splatpath_t) * r_shadow_bouncegrid_state.maxsplatpaths);
3220 // figure out what we want to interact with
3221 if (settings.hitmodels)
3222 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;// | SUPERCONTENTS_LIQUIDSMASK;
3224 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
3225 skipsupercontentsmask = SUPERCONTENTS_SKY; // this allows the e1m5 sky shadow to work by ignoring the sky surfaces
3226 maxbounce = settings.maxbounce;
3228 for (lightindex = 0;lightindex < range2;lightindex++)
3230 if (lightindex < range)
3232 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3235 rtlight = &light->rtlight;
3238 rtlight = r_refdef.scene.lights[lightindex - range];
3239 // note that this code used to keep track of residual photons and
3240 // distribute them evenly to achieve exactly a desired photon count,
3241 // but that caused unwanted flickering in dynamic mode
3242 shootparticles = (int)floor(rtlight->photons * photonscaling);
3243 // skip if we won't be shooting any photons
3244 if (!shootparticles)
3246 radius = rtlight->radius * settings.lightradiusscale;
3247 s = settings.particleintensity / shootparticles;
3248 VectorScale(rtlight->photoncolor, s, baseshotcolor);
3249 r_refdef.stats[r_stat_bouncegrid_lights]++;
3250 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
3251 switch (settings.stablerandom)
3256 Math_RandomSeed_FromInt(&randomseed, lightindex * 11937);
3257 // prime the random number generator a bit
3258 Math_crandomf(&randomseed);
3261 seed = lightindex * 11937;
3262 // prime the random number generator a bit
3266 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
3268 VectorCopy(baseshotcolor, shotcolor);
3269 VectorCopy(rtlight->shadoworigin, clipstart);
3270 switch (settings.stablerandom)
3274 VectorRandom(clipend);
3275 if (settings.bounceanglediffuse)
3277 // we want random to be stable, so we still have to do all the random we would have done
3278 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3279 VectorRandom(bouncerandom[bouncecount]);
3284 VectorLehmerRandom(&randomseed, clipend);
3285 if (settings.bounceanglediffuse)
3287 // we want random to be stable, so we still have to do all the random we would have done
3288 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3289 VectorLehmerRandom(&randomseed, bouncerandom[bouncecount]);
3294 VectorCheeseRandom(seed, clipend);
3295 if (settings.bounceanglediffuse)
3297 // we want random to be stable, so we still have to do all the random we would have done
3298 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3299 VectorCheeseRandom(seed, bouncerandom[bouncecount]);
3303 VectorMA(clipstart, radius, clipend, clipend);
3304 for (bouncecount = 0;;bouncecount++)
3306 r_refdef.stats[r_stat_bouncegrid_traces]++;
3307 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
3308 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
3309 if (settings.staticmode || settings.stablerandom <= 0)
3311 // static mode fires a LOT of rays but none of them are identical, so they are not cached
3312 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
3313 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);
3317 // dynamic mode fires many rays and most will match the cache from the previous frame
3318 cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask, skipsupercontentsmask);
3320 if (bouncecount > 0 || settings.includedirectlighting)
3323 VectorCopy(cliptrace.endpos, hitpos);
3324 R_Shadow_BounceGrid_AddSplatPath(clipstart, hitpos, shotcolor);
3326 if (cliptrace.fraction >= 1.0f)
3328 r_refdef.stats[r_stat_bouncegrid_hits]++;
3329 if (bouncecount >= maxbounce)
3331 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
3332 // also clamp the resulting color to never add energy, even if the user requests extreme values
3333 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
3334 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
3336 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
3337 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
3338 surfcolor[0] = min(surfcolor[0], 1.0f);
3339 surfcolor[1] = min(surfcolor[1], 1.0f);
3340 surfcolor[2] = min(surfcolor[2], 1.0f);
3341 VectorMultiply(shotcolor, surfcolor, shotcolor);
3342 if (VectorLength2(baseshotcolor) == 0.0f)
3344 r_refdef.stats[r_stat_bouncegrid_bounces]++;
3345 if (settings.bounceanglediffuse)
3347 // random direction, primarily along plane normal
3348 s = VectorDistance(cliptrace.endpos, clipend);
3349 VectorMA(cliptrace.plane.normal, 0.95f, bouncerandom[bouncecount], clipend);
3350 VectorNormalize(clipend);
3351 VectorScale(clipend, s, clipend);
3355 // reflect the remaining portion of the line across plane normal
3356 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
3357 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
3359 // calculate the new line start and end
3360 VectorCopy(cliptrace.endpos, clipstart);
3361 VectorAdd(clipstart, clipend, clipend);
3367 void R_Shadow_UpdateBounceGridTexture(void)
3369 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3370 r_shadow_bouncegrid_settings_t settings;
3371 qboolean enable = false;
3372 qboolean settingschanged;
3373 unsigned int range; // number of world lights
3374 unsigned int range1; // number of dynamic lights (or zero if disabled)
3375 unsigned int range2; // range+range1
3376 float photonscaling;
3378 enable = R_Shadow_BounceGrid_CheckEnable(flag);
3380 R_Shadow_BounceGrid_GenerateSettings(&settings);
3382 // changing intensity does not require an update
3383 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
3385 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
3387 // when settings change, we free everything as it is just simpler that way.
3388 if (settingschanged || !enable)
3390 // not enabled, make sure we free anything we don't need anymore.
3391 if (r_shadow_bouncegrid_state.texture)
3393 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3394 r_shadow_bouncegrid_state.texture = NULL;
3396 r_shadow_bouncegrid_state.numpixels = 0;
3397 r_shadow_bouncegrid_state.directional = false;
3403 // if all the settings seem identical to the previous update, return
3404 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
3407 // store the new settings
3408 r_shadow_bouncegrid_state.settings = settings;
3410 R_Shadow_BounceGrid_UpdateSpacing();
3412 // get the range of light numbers we'll be looping over:
3413 // range = static lights
3414 // range1 = dynamic lights (optional)
3415 // range2 = range + range1
3416 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3417 range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
3418 range2 = range + range1;
3420 // calculate weighting factors for distributing photons among the lights
3421 R_Shadow_BounceGrid_AssignPhotons(&settings, range, range1, range2, flag, &photonscaling);
3423 // trace the photons from lights and accumulate illumination
3424 R_Shadow_BounceGrid_TracePhotons(settings, range, range1, range2, photonscaling, flag);
3426 // clear the texture
3427 R_Shadow_BounceGrid_ClearPixels();
3429 // accumulate the light splatting into texture
3430 R_Shadow_BounceGrid_PerformSplats();
3432 // apply a mild blur filter to the texture
3433 R_Shadow_BounceGrid_BlurPixels();
3435 // convert the pixels to lower precision and upload the texture
3436 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
3439 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
3441 R_Shadow_RenderMode_Reset();
3442 GL_BlendFunc(GL_ONE, GL_ONE);
3443 GL_DepthRange(0, 1);
3444 GL_DepthTest(r_showshadowvolumes.integer < 2);
3445 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
3446 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
3447 GL_CullFace(GL_NONE);
3448 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
3451 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
3453 R_Shadow_RenderMode_Reset();
3454 GL_BlendFunc(GL_ONE, GL_ONE);
3455 GL_DepthRange(0, 1);
3456 GL_DepthTest(r_showlighting.integer < 2);
3457 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
3459 GL_DepthFunc(GL_EQUAL);
3460 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
3461 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
3464 void R_Shadow_RenderMode_End(void)
3466 R_Shadow_RenderMode_Reset();
3467 R_Shadow_RenderMode_ActiveLight(NULL);
3469 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3470 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3473 int bboxedges[12][2] =
3492 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
3494 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
3496 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
3497 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
3498 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
3499 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
3502 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
3503 return true; // invisible
3504 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
3505 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
3506 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
3507 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
3508 r_refdef.stats[r_stat_lights_scissored]++;
3512 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
3515 const float *vertex3f;
3516 const float *normal3f;
3518 float dist, dot, distintensity, shadeintensity, v[3], n[3];
3519 switch (r_shadow_rendermode)
3521 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3522 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3523 if (VectorLength2(diffusecolor) > 0)
3525 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)
3527 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3528 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3529 if ((dot = DotProduct(n, v)) < 0)
3531 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3532 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
3535 VectorCopy(ambientcolor, color4f);
3536 if (r_refdef.fogenabled)
3539 f = RSurf_FogVertex(vertex3f);
3540 VectorScale(color4f, f, color4f);
3547 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3549 VectorCopy(ambientcolor, color4f);
3550 if (r_refdef.fogenabled)
3553 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3554 f = RSurf_FogVertex(vertex3f);
3555 VectorScale(color4f + 4*i, f, color4f);
3561 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3562 if (VectorLength2(diffusecolor) > 0)
3564 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)
3566 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3567 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3569 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3570 if ((dot = DotProduct(n, v)) < 0)
3572 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3573 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3574 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3575 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3579 color4f[0] = ambientcolor[0] * distintensity;
3580 color4f[1] = ambientcolor[1] * distintensity;
3581 color4f[2] = ambientcolor[2] * distintensity;
3583 if (r_refdef.fogenabled)
3586 f = RSurf_FogVertex(vertex3f);
3587 VectorScale(color4f, f, color4f);
3591 VectorClear(color4f);
3597 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3599 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3600 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3602 color4f[0] = ambientcolor[0] * distintensity;
3603 color4f[1] = ambientcolor[1] * distintensity;
3604 color4f[2] = ambientcolor[2] * distintensity;
3605 if (r_refdef.fogenabled)
3608 f = RSurf_FogVertex(vertex3f);
3609 VectorScale(color4f, f, color4f);
3613 VectorClear(color4f);
3618 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3619 if (VectorLength2(diffusecolor) > 0)
3621 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)
3623 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3624 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3626 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3627 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3628 if ((dot = DotProduct(n, v)) < 0)
3630 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3631 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3632 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3633 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3637 color4f[0] = ambientcolor[0] * distintensity;
3638 color4f[1] = ambientcolor[1] * distintensity;
3639 color4f[2] = ambientcolor[2] * distintensity;
3641 if (r_refdef.fogenabled)
3644 f = RSurf_FogVertex(vertex3f);
3645 VectorScale(color4f, f, color4f);
3649 VectorClear(color4f);
3655 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3657 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3658 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3660 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3661 color4f[0] = ambientcolor[0] * distintensity;
3662 color4f[1] = ambientcolor[1] * distintensity;
3663 color4f[2] = ambientcolor[2] * distintensity;
3664 if (r_refdef.fogenabled)
3667 f = RSurf_FogVertex(vertex3f);
3668 VectorScale(color4f, f, color4f);
3672 VectorClear(color4f);
3682 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3684 // used to display how many times a surface is lit for level design purposes
3685 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3686 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3690 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
3692 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3693 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
3697 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3704 int newnumtriangles;
3708 int maxtriangles = 1024;
3709 int newelements[1024*3];
3710 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3711 for (renders = 0;renders < 4;renders++)
3716 newnumtriangles = 0;
3718 // due to low fillrate on the cards this vertex lighting path is
3719 // designed for, we manually cull all triangles that do not
3720 // contain a lit vertex
3721 // this builds batches of triangles from multiple surfaces and
3722 // renders them at once
3723 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3725 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3727 if (newnumtriangles)
3729 newfirstvertex = min(newfirstvertex, e[0]);
3730 newlastvertex = max(newlastvertex, e[0]);
3734 newfirstvertex = e[0];
3735 newlastvertex = e[0];
3737 newfirstvertex = min(newfirstvertex, e[1]);
3738 newlastvertex = max(newlastvertex, e[1]);
3739 newfirstvertex = min(newfirstvertex, e[2]);
3740 newlastvertex = max(newlastvertex, e[2]);
3746 if (newnumtriangles >= maxtriangles)
3748 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3749 newnumtriangles = 0;
3755 if (newnumtriangles >= 1)
3757 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3760 // if we couldn't find any lit triangles, exit early
3763 // now reduce the intensity for the next overbright pass
3764 // we have to clamp to 0 here incase the drivers have improper
3765 // handling of negative colors
3766 // (some old drivers even have improper handling of >1 color)
3768 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3770 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3772 c[0] = max(0, c[0] - 1);
3773 c[1] = max(0, c[1] - 1);
3774 c[2] = max(0, c[2] - 1);
3786 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
3788 // OpenGL 1.1 path (anything)
3789 float ambientcolorbase[3], diffusecolorbase[3];
3790 float ambientcolorpants[3], diffusecolorpants[3];
3791 float ambientcolorshirt[3], diffusecolorshirt[3];
3792 const float *surfacecolor = rsurface.texture->dlightcolor;
3793 const float *surfacepants = rsurface.colormap_pantscolor;
3794 const float *surfaceshirt = rsurface.colormap_shirtcolor;
3795 rtexture_t *basetexture = rsurface.texture->basetexture;
3796 rtexture_t *pantstexture = rsurface.texture->pantstexture;
3797 rtexture_t *shirttexture = rsurface.texture->shirttexture;
3798 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3799 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3800 ambientscale *= 2 * r_refdef.view.colorscale;
3801 diffusescale *= 2 * r_refdef.view.colorscale;
3802 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3803 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3804 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3805 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3806 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3807 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
3808 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3809 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
3810 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3811 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
3812 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
3813 R_Mesh_TexBind(0, basetexture);
3814 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
3815 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
3816 switch(r_shadow_rendermode)
3818 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3819 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
3820 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3821 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3822 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3824 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3825 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
3826 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
3827 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
3828 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3830 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3831 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
3832 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3833 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3834 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3836 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3841 //R_Mesh_TexBind(0, basetexture);
3842 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
3845 R_Mesh_TexBind(0, pantstexture);
3846 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
3850 R_Mesh_TexBind(0, shirttexture);
3851 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
3855 extern cvar_t gl_lightmaps;
3856 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3858 float ambientscale, diffusescale, specularscale;
3860 float lightcolor[3];
3861 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
3862 ambientscale = rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient;
3863 diffusescale = rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient);
3864 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3865 if (!r_shadow_usenormalmap.integer)
3867 ambientscale += 1.0f * diffusescale;
3871 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
3873 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
3876 VectorNegate(lightcolor, lightcolor);
3877 GL_BlendEquationSubtract(true);
3879 RSurf_SetupDepthAndCulling();
3880 switch (r_shadow_rendermode)
3882 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3883 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3884 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
3886 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3887 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
3889 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3890 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3891 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3892 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3893 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
3896 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3900 GL_BlendEquationSubtract(false);
3903 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)
3905 matrix4x4_t tempmatrix = *matrix;
3906 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3908 // if this light has been compiled before, free the associated data
3909 R_RTLight_Uncompile(rtlight);
3911 // clear it completely to avoid any lingering data
3912 memset(rtlight, 0, sizeof(*rtlight));
3914 // copy the properties
3915 rtlight->matrix_lighttoworld = tempmatrix;
3916 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3917 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3918 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3919 VectorCopy(color, rtlight->color);
3920 rtlight->cubemapname[0] = 0;
3921 if (cubemapname && cubemapname[0])
3922 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3923 rtlight->shadow = shadow;
3924 rtlight->corona = corona;
3925 rtlight->style = style;
3926 rtlight->isstatic = isstatic;
3927 rtlight->coronasizescale = coronasizescale;
3928 rtlight->ambientscale = ambientscale;
3929 rtlight->diffusescale = diffusescale;
3930 rtlight->specularscale = specularscale;
3931 rtlight->flags = flags;
3933 // compute derived data
3934 //rtlight->cullradius = rtlight->radius;
3935 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3936 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3937 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3938 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3939 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3940 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3941 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3944 // compiles rtlight geometry
3945 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3946 void R_RTLight_Compile(rtlight_t *rtlight)
3949 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3950 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3951 entity_render_t *ent = r_refdef.scene.worldentity;
3952 dp_model_t *model = r_refdef.scene.worldmodel;
3953 unsigned char *data;
3956 // compile the light
3957 rtlight->compiled = true;
3958 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3959 rtlight->static_numleafs = 0;
3960 rtlight->static_numleafpvsbytes = 0;
3961 rtlight->static_leaflist = NULL;
3962 rtlight->static_leafpvs = NULL;
3963 rtlight->static_numsurfaces = 0;
3964 rtlight->static_surfacelist = NULL;
3965 rtlight->static_shadowmap_receivers = 0x3F;
3966 rtlight->static_shadowmap_casters = 0x3F;
3967 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3968 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3969 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3970 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3971 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3972 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3974 if (model && model->GetLightInfo)
3976 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3977 r_shadow_compilingrtlight = rtlight;
3978 R_FrameData_SetMark();
3979 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);
3980 R_FrameData_ReturnToMark();
3981 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3982 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3983 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3984 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3985 rtlight->static_numsurfaces = numsurfaces;
3986 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3987 rtlight->static_numleafs = numleafs;
3988 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3989 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3990 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3991 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3992 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3993 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3994 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3995 if (rtlight->static_numsurfaces)
3996 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3997 if (rtlight->static_numleafs)
3998 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3999 if (rtlight->static_numleafpvsbytes)
4000 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
4001 if (rtlight->static_numshadowtrispvsbytes)
4002 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
4003 if (rtlight->static_numlighttrispvsbytes)
4004 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
4005 R_FrameData_SetMark();
4006 switch (rtlight->shadowmode)
4008 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4009 if (model->CompileShadowMap && rtlight->shadow)
4010 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
4013 if (model->CompileShadowVolume && rtlight->shadow)
4014 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
4017 R_FrameData_ReturnToMark();
4018 // now we're done compiling the rtlight
4019 r_shadow_compilingrtlight = NULL;
4023 // use smallest available cullradius - box radius or light radius
4024 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
4025 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
4027 shadowzpasstris = 0;
4028 if (rtlight->static_meshchain_shadow_zpass)
4029 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
4030 shadowzpasstris += mesh->numtriangles;
4032 shadowzfailtris = 0;
4033 if (rtlight->static_meshchain_shadow_zfail)
4034 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
4035 shadowzfailtris += mesh->numtriangles;
4038 if (rtlight->static_numlighttrispvsbytes)
4039 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
4040 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
4044 if (rtlight->static_numshadowtrispvsbytes)
4045 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
4046 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
4049 if (developer_extra.integer)
4050 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);
4053 void R_RTLight_Uncompile(rtlight_t *rtlight)
4055 if (rtlight->compiled)
4057 if (rtlight->static_meshchain_shadow_zpass)
4058 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
4059 rtlight->static_meshchain_shadow_zpass = NULL;
4060 if (rtlight->static_meshchain_shadow_zfail)
4061 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
4062 rtlight->static_meshchain_shadow_zfail = NULL;
4063 if (rtlight->static_meshchain_shadow_shadowmap)
4064 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
4065 rtlight->static_meshchain_shadow_shadowmap = NULL;
4066 // these allocations are grouped
4067 if (rtlight->static_surfacelist)
4068 Mem_Free(rtlight->static_surfacelist);
4069 rtlight->static_numleafs = 0;
4070 rtlight->static_numleafpvsbytes = 0;
4071 rtlight->static_leaflist = NULL;
4072 rtlight->static_leafpvs = NULL;
4073 rtlight->static_numsurfaces = 0;
4074 rtlight->static_surfacelist = NULL;
4075 rtlight->static_numshadowtrispvsbytes = 0;
4076 rtlight->static_shadowtrispvs = NULL;
4077 rtlight->static_numlighttrispvsbytes = 0;
4078 rtlight->static_lighttrispvs = NULL;
4079 rtlight->compiled = false;
4083 void R_Shadow_UncompileWorldLights(void)
4087 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4088 for (lightindex = 0;lightindex < range;lightindex++)
4090 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4093 R_RTLight_Uncompile(&light->rtlight);
4097 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
4101 // reset the count of frustum planes
4102 // see rtlight->cached_frustumplanes definition for how much this array
4104 rtlight->cached_numfrustumplanes = 0;
4106 if (r_trippy.integer)
4109 // haven't implemented a culling path for ortho rendering
4110 if (!r_refdef.view.useperspective)
4112 // check if the light is on screen and copy the 4 planes if it is
4113 for (i = 0;i < 4;i++)
4114 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4117 for (i = 0;i < 4;i++)
4118 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4123 // generate a deformed frustum that includes the light origin, this is
4124 // used to cull shadow casting surfaces that can not possibly cast a
4125 // shadow onto the visible light-receiving surfaces, which can be a
4128 // if the light origin is onscreen the result will be 4 planes exactly
4129 // if the light origin is offscreen on only one axis the result will
4130 // be exactly 5 planes (split-side case)
4131 // if the light origin is offscreen on two axes the result will be
4132 // exactly 4 planes (stretched corner case)
4133 for (i = 0;i < 4;i++)
4135 // quickly reject standard frustum planes that put the light
4136 // origin outside the frustum
4137 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4140 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4142 // if all the standard frustum planes were accepted, the light is onscreen
4143 // otherwise we need to generate some more planes below...
4144 if (rtlight->cached_numfrustumplanes < 4)
4146 // at least one of the stock frustum planes failed, so we need to
4147 // create one or two custom planes to enclose the light origin
4148 for (i = 0;i < 4;i++)
4150 // create a plane using the view origin and light origin, and a
4151 // single point from the frustum corner set
4152 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
4153 VectorNormalize(plane.normal);
4154 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
4155 // see if this plane is backwards and flip it if so
4156 for (j = 0;j < 4;j++)
4157 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4161 VectorNegate(plane.normal, plane.normal);
4163 // flipped plane, test again to see if it is now valid
4164 for (j = 0;j < 4;j++)
4165 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4167 // if the plane is still not valid, then it is dividing the
4168 // frustum and has to be rejected
4172 // we have created a valid plane, compute extra info
4173 PlaneClassify(&plane);
4175 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4177 // if we've found 5 frustum planes then we have constructed a
4178 // proper split-side case and do not need to keep searching for
4179 // planes to enclose the light origin
4180 if (rtlight->cached_numfrustumplanes == 5)
4188 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
4190 plane = rtlight->cached_frustumplanes[i];
4191 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));
4196 // now add the light-space box planes if the light box is rotated, as any
4197 // caster outside the oriented light box is irrelevant (even if it passed
4198 // the worldspace light box, which is axial)
4199 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
4201 for (i = 0;i < 6;i++)
4205 v[i >> 1] = (i & 1) ? -1 : 1;
4206 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
4207 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
4208 plane.dist = VectorNormalizeLength(plane.normal);
4209 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
4210 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4216 // add the world-space reduced box planes
4217 for (i = 0;i < 6;i++)
4219 VectorClear(plane.normal);
4220 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
4221 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
4222 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4231 // reduce all plane distances to tightly fit the rtlight cull box, which
4233 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4234 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4235 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4236 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4237 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4238 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4239 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4240 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4241 oldnum = rtlight->cached_numfrustumplanes;
4242 rtlight->cached_numfrustumplanes = 0;
4243 for (j = 0;j < oldnum;j++)
4245 // find the nearest point on the box to this plane
4246 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
4247 for (i = 1;i < 8;i++)
4249 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
4250 if (bestdist > dist)
4253 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);
4254 // if the nearest point is near or behind the plane, we want this
4255 // plane, otherwise the plane is useless as it won't cull anything
4256 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
4258 PlaneClassify(&rtlight->cached_frustumplanes[j]);
4259 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
4266 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
4270 RSurf_ActiveWorldEntity();
4272 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4275 GL_CullFace(GL_NONE);
4276 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
4277 for (;mesh;mesh = mesh->next)
4279 if (!mesh->sidetotals[r_shadow_shadowmapside])
4281 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
4282 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4283 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);
4287 else if (r_refdef.scene.worldentity->model)
4288 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);
4290 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4293 static void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
4295 qboolean zpass = false;
4298 int surfacelistindex;
4299 msurface_t *surface;
4301 // if triangle neighbors are disabled, shadowvolumes are disabled
4302 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
4305 RSurf_ActiveWorldEntity();
4307 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4310 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
4312 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
4313 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
4315 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
4316 for (;mesh;mesh = mesh->next)
4318 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->numtriangles;
4319 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4320 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
4322 // increment stencil if frontface is infront of depthbuffer
4323 GL_CullFace(r_refdef.view.cullface_back);
4324 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
4325 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);
4326 // decrement stencil if backface is infront of depthbuffer
4327 GL_CullFace(r_refdef.view.cullface_front);
4328 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
4330 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
4332 // decrement stencil if backface is behind depthbuffer
4333 GL_CullFace(r_refdef.view.cullface_front);
4334 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
4335 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);
4336 // increment stencil if frontface is behind depthbuffer
4337 GL_CullFace(r_refdef.view.cullface_back);
4338 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
4340 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);
4344 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
4346 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
4347 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
4348 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
4350 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
4351 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
4352 if (CHECKPVSBIT(trispvs, t))
4353 shadowmarklist[numshadowmark++] = t;
4355 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);
4357 else if (numsurfaces)
4359 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);
4362 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4365 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
4367 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
4368 vec_t relativeshadowradius;
4369 RSurf_ActiveModelEntity(ent, false, false, false);
4370 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
4371 // we need to re-init the shader for each entity because the matrix changed
4372 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
4373 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
4374 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
4375 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
4376 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
4377 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
4378 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
4379 switch (r_shadow_rendermode)
4381 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
4382 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4385 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4388 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4391 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
4393 // set up properties for rendering light onto this entity
4394 RSurf_ActiveModelEntity(ent, true, true, false);
4395 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
4396 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4397 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4398 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4401 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
4403 if (!r_refdef.scene.worldmodel->DrawLight)
4406 // set up properties for rendering light onto this entity
4407 RSurf_ActiveWorldEntity();
4408 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
4409 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4410 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4411 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4413 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
4415 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4418 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
4420 dp_model_t *model = ent->model;
4421 if (!model->DrawLight)
4424 R_Shadow_SetupEntityLight(ent);
4426 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
4428 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4431 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
4435 int numleafs, numsurfaces;
4436 int *leaflist, *surfacelist;
4437 unsigned char *leafpvs;
4438 unsigned char *shadowtrispvs;
4439 unsigned char *lighttrispvs;
4440 //unsigned char *surfacesides;
4441 int numlightentities;
4442 int numlightentities_noselfshadow;
4443 int numshadowentities;
4444 int numshadowentities_noselfshadow;
4445 // FIXME: bounds check lightentities and shadowentities, etc.
4446 static entity_render_t *lightentities[MAX_EDICTS];
4447 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
4448 static entity_render_t *shadowentities[MAX_EDICTS];
4449 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
4451 qboolean castshadows;
4453 rtlight->draw = false;
4454 rtlight->cached_numlightentities = 0;
4455 rtlight->cached_numlightentities_noselfshadow = 0;
4456 rtlight->cached_numshadowentities = 0;
4457 rtlight->cached_numshadowentities_noselfshadow = 0;
4458 rtlight->cached_numsurfaces = 0;
4459 rtlight->cached_lightentities = NULL;
4460 rtlight->cached_lightentities_noselfshadow = NULL;
4461 rtlight->cached_shadowentities = NULL;
4462 rtlight->cached_shadowentities_noselfshadow = NULL;
4463 rtlight->cached_shadowtrispvs = NULL;
4464 rtlight->cached_lighttrispvs = NULL;
4465 rtlight->cached_surfacelist = NULL;
4466 rtlight->shadowmapsidesize = 0;
4468 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
4469 // skip lights that are basically invisible (color 0 0 0)
4470 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
4472 // loading is done before visibility checks because loading should happen
4473 // all at once at the start of a level, not when it stalls gameplay.
4474 // (especially important to benchmarks)
4476 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
4478 if (rtlight->compiled)
4479 R_RTLight_Uncompile(rtlight);
4480 R_RTLight_Compile(rtlight);
4484 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
4486 // look up the light style value at this time
4487 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4488 VectorScale(rtlight->color, f, rtlight->currentcolor);
4490 if (rtlight->selected)
4492 f = 2 + sin(realtime * M_PI * 4.0);
4493 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
4497 // if lightstyle is currently off, don't draw the light
4498 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
4501 // skip processing on corona-only lights
4505 // if the light box is offscreen, skip it
4506 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
4509 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
4510 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
4512 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4514 // 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
4515 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
4518 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
4520 // compiled light, world available and can receive realtime lighting
4521 // retrieve leaf information
4522 numleafs = rtlight->static_numleafs;
4523 leaflist = rtlight->static_leaflist;
4524 leafpvs = rtlight->static_leafpvs;
4525 numsurfaces = rtlight->static_numsurfaces;
4526 surfacelist = rtlight->static_surfacelist;
4527 //surfacesides = NULL;
4528 shadowtrispvs = rtlight->static_shadowtrispvs;
4529 lighttrispvs = rtlight->static_lighttrispvs;
4531 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4533 // dynamic light, world available and can receive realtime lighting
4534 // calculate lit surfaces and leafs
4535 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);
4536 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4537 leaflist = r_shadow_buffer_leaflist;
4538 leafpvs = r_shadow_buffer_leafpvs;
4539 surfacelist = r_shadow_buffer_surfacelist;
4540 //surfacesides = r_shadow_buffer_surfacesides;
4541 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4542 lighttrispvs = r_shadow_buffer_lighttrispvs;
4543 // if the reduced leaf bounds are offscreen, skip it
4544 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4555 //surfacesides = NULL;
4556 shadowtrispvs = NULL;
4557 lighttrispvs = NULL;
4559 // check if light is illuminating any visible leafs
4562 for (i = 0; i < numleafs; i++)
4563 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4569 // make a list of lit entities and shadow casting entities
4570 numlightentities = 0;
4571 numlightentities_noselfshadow = 0;
4572 numshadowentities = 0;
4573 numshadowentities_noselfshadow = 0;
4575 // add dynamic entities that are lit by the light
4576 for (i = 0; i < r_refdef.scene.numentities; i++)
4579 entity_render_t *ent = r_refdef.scene.entities[i];
4581 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4583 // skip the object entirely if it is not within the valid
4584 // shadow-casting region (which includes the lit region)
4585 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
4587 if (!(model = ent->model))
4589 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4591 // this entity wants to receive light, is visible, and is
4592 // inside the light box
4593 // TODO: check if the surfaces in the model can receive light
4594 // so now check if it's in a leaf seen by the light
4595 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))
4597 if (ent->flags & RENDER_NOSELFSHADOW)
4598 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
4600 lightentities[numlightentities++] = ent;
4601 // since it is lit, it probably also casts a shadow...
4602 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4603 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4604 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4606 // note: exterior models without the RENDER_NOSELFSHADOW
4607 // flag still create a RENDER_NOSELFSHADOW shadow but
4608 // are lit normally, this means that they are
4609 // self-shadowing but do not shadow other
4610 // RENDER_NOSELFSHADOW entities such as the gun
4611 // (very weird, but keeps the player shadow off the gun)
4612 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4613 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4615 shadowentities[numshadowentities++] = ent;
4618 else if (ent->flags & RENDER_SHADOW)
4620 // this entity is not receiving light, but may still need to
4622 // TODO: check if the surfaces in the model can cast shadow
4623 // now check if it is in a leaf seen by the light
4624 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))
4626 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4627 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4628 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4630 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4631 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4633 shadowentities[numshadowentities++] = ent;
4638 // return if there's nothing at all to light
4639 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4642 // count this light in the r_speeds
4643 r_refdef.stats[r_stat_lights]++;
4645 // flag it as worth drawing later
4646 rtlight->draw = true;
4648 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
4649 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4651 numshadowentities = numshadowentities_noselfshadow = 0;
4652 rtlight->castshadows = castshadows;
4654 // cache all the animated entities that cast a shadow but are not visible
4655 for (i = 0; i < numshadowentities; i++)
4656 R_AnimCache_GetEntity(shadowentities[i], false, false);
4657 for (i = 0; i < numshadowentities_noselfshadow; i++)
4658 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4660 // 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)
4661 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
4663 for (i = 0; i < numshadowentities_noselfshadow; i++)
4664 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
4665 numshadowentities_noselfshadow = 0;
4668 // we can convert noselfshadow to regular if there are no casters of that type
4669 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
4671 for (i = 0; i < numlightentities_noselfshadow; i++)
4672 lightentities[numlightentities++] = lightentities_noselfshadow[i];
4673 numlightentities_noselfshadow = 0;
4676 // allocate some temporary memory for rendering this light later in the frame
4677 // reusable buffers need to be copied, static data can be used as-is
4678 rtlight->cached_numlightentities = numlightentities;
4679 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
4680 rtlight->cached_numshadowentities = numshadowentities;
4681 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4682 rtlight->cached_numsurfaces = numsurfaces;
4683 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4684 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4685 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4686 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4687 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4689 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4690 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4691 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4692 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4693 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4697 // compiled light data
4698 rtlight->cached_shadowtrispvs = shadowtrispvs;
4699 rtlight->cached_lighttrispvs = lighttrispvs;
4700 rtlight->cached_surfacelist = surfacelist;
4703 if (R_Shadow_ShadowMappingEnabled())
4705 // figure out the shadowmapping parameters for this light
4706 vec3_t nearestpoint;
4709 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4710 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4711 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4712 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4713 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
4714 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4715 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4716 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4717 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
4721 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
4725 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4726 int numlightentities;
4727 int numlightentities_noselfshadow;
4728 int numshadowentities;
4729 int numshadowentities_noselfshadow;
4730 entity_render_t **lightentities;
4731 entity_render_t **lightentities_noselfshadow;
4732 entity_render_t **shadowentities;
4733 entity_render_t **shadowentities_noselfshadow;
4735 static unsigned char entitysides[MAX_EDICTS];
4736 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4742 matrix4x4_t radiustolight;
4744 // check if we cached this light this frame (meaning it is worth drawing)
4745 if (!rtlight->draw || !rtlight->castshadows)
4748 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
4749 if (rtlight->shadowmapatlassidesize == 0)
4751 rtlight->castshadows = false;
4755 // set up a scissor rectangle for this light
4756 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4759 // don't let sound skip if going slow
4760 if (r_refdef.scene.extraupdate)
4763 numlightentities = rtlight->cached_numlightentities;
4764 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4765 numshadowentities = rtlight->cached_numshadowentities;
4766 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4767 numsurfaces = rtlight->cached_numsurfaces;
4768 lightentities = rtlight->cached_lightentities;
4769 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4770 shadowentities = rtlight->cached_shadowentities;
4771 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4772 shadowtrispvs = rtlight->cached_shadowtrispvs;
4773 lighttrispvs = rtlight->cached_lighttrispvs;
4774 surfacelist = rtlight->cached_surfacelist;
4776 // make this the active rtlight for rendering purposes
4777 R_Shadow_RenderMode_ActiveLight(rtlight);
4779 radiustolight = rtlight->matrix_worldtolight;
4780 Matrix4x4_Abs(&radiustolight);
4782 size = rtlight->shadowmapatlassidesize;
4783 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4785 surfacesides = NULL;
4790 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4792 castermask = rtlight->static_shadowmap_casters;
4793 receivermask = rtlight->static_shadowmap_receivers;
4797 surfacesides = r_shadow_buffer_surfacesides;
4798 for (i = 0; i < numsurfaces; i++)
4800 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4801 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4802 castermask |= surfacesides[i];
4803 receivermask |= surfacesides[i];
4808 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
4809 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4810 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
4811 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4813 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4817 for (i = 0; i < numshadowentities; i++)
4818 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4819 for (i = 0; i < numshadowentities_noselfshadow; i++)
4820 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4823 // there is no need to render shadows for sides that have no receivers...
4824 castermask &= receivermask;
4826 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
4828 // render shadow casters into shadowmaps for this light
4829 for (side = 0; side < 6; side++)
4831 int bit = 1 << side;
4832 if (castermask & bit)
4834 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
4836 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4837 for (i = 0; i < numshadowentities; i++)
4838 if (entitysides[i] & bit)
4839 R_Shadow_DrawEntityShadow(shadowentities[i]);
4840 for (i = 0; i < numshadowentities_noselfshadow; i++)
4841 if (entitysides_noselfshadow[i] & bit)
4842 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4845 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
4846 if (numshadowentities_noselfshadow)
4848 for (side = 0; side < 6; side++)
4850 int bit = 1 << side;
4851 if (castermask & bit)
4853 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
4855 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4856 for (i = 0; i < numshadowentities; i++)
4857 if (entitysides[i] & bit)
4858 R_Shadow_DrawEntityShadow(shadowentities[i]);
4864 static void R_Shadow_DrawLight(rtlight_t *rtlight)
4868 unsigned char *shadowtrispvs, *lighttrispvs;
4869 int numlightentities;
4870 int numlightentities_noselfshadow;
4871 int numshadowentities;
4872 int numshadowentities_noselfshadow;
4873 entity_render_t **lightentities;
4874 entity_render_t **lightentities_noselfshadow;
4875 entity_render_t **shadowentities;
4876 entity_render_t **shadowentities_noselfshadow;
4878 qboolean castshadows;
4880 // check if we cached this light this frame (meaning it is worth drawing)
4884 // set up a scissor rectangle for this light
4885 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4888 // don't let sound skip if going slow
4889 if (r_refdef.scene.extraupdate)
4892 numlightentities = rtlight->cached_numlightentities;
4893 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4894 numshadowentities = rtlight->cached_numshadowentities;
4895 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4896 numsurfaces = rtlight->cached_numsurfaces;
4897 lightentities = rtlight->cached_lightentities;
4898 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4899 shadowentities = rtlight->cached_shadowentities;
4900 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4901 shadowtrispvs = rtlight->cached_shadowtrispvs;
4902 lighttrispvs = rtlight->cached_lighttrispvs;
4903 surfacelist = rtlight->cached_surfacelist;
4904 castshadows = rtlight->castshadows;
4906 // make this the active rtlight for rendering purposes
4907 R_Shadow_RenderMode_ActiveLight(rtlight);
4909 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4911 // optionally draw visible shape of the shadow volumes
4912 // for performance analysis by level designers
4913 R_Shadow_RenderMode_VisibleShadowVolumes();
4915 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4916 for (i = 0;i < numshadowentities;i++)
4917 R_Shadow_DrawEntityShadow(shadowentities[i]);
4918 for (i = 0;i < numshadowentities_noselfshadow;i++)
4919 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4920 R_Shadow_RenderMode_VisibleLighting(false, false);
4923 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4925 // optionally draw the illuminated areas
4926 // for performance analysis by level designers
4927 R_Shadow_RenderMode_VisibleLighting(false, false);
4929 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4930 for (i = 0;i < numlightentities;i++)
4931 R_Shadow_DrawEntityLight(lightentities[i]);
4932 for (i = 0;i < numlightentities_noselfshadow;i++)
4933 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4936 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4940 float shadowmapoffsetnoselfshadow = 0;
4941 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4942 Matrix4x4_Abs(&radiustolight);
4944 size = rtlight->shadowmapatlassidesize;
4945 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4947 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
4949 if (rtlight->cached_numshadowentities_noselfshadow)
4950 shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
4952 // render lighting using the depth texture as shadowmap
4953 // draw lighting in the unmasked areas
4954 if (numsurfaces + numlightentities)
4956 R_Shadow_RenderMode_Lighting(false, false, true, false);
4957 // draw lighting in the unmasked areas
4959 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4960 for (i = 0; i < numlightentities; i++)
4961 R_Shadow_DrawEntityLight(lightentities[i]);
4963 // offset to the noselfshadow part of the atlas and draw those too
4964 if (numlightentities_noselfshadow)
4966 R_Shadow_RenderMode_Lighting(false, false, true, true);
4967 for (i = 0; i < numlightentities_noselfshadow; i++)
4968 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4971 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
4972 if (r_shadow_usingdeferredprepass)
4973 R_Shadow_RenderMode_DrawDeferredLight(true);
4975 else if (castshadows && vid.stencil)
4977 // draw stencil shadow volumes to mask off pixels that are in shadow
4978 // so that they won't receive lighting
4979 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4980 R_Shadow_ClearStencil();
4983 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4984 for (i = 0;i < numshadowentities;i++)
4985 R_Shadow_DrawEntityShadow(shadowentities[i]);
4987 // draw lighting in the unmasked areas
4988 R_Shadow_RenderMode_Lighting(true, false, false, false);
4989 for (i = 0;i < numlightentities_noselfshadow;i++)
4990 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4992 for (i = 0;i < numshadowentities_noselfshadow;i++)
4993 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4995 // draw lighting in the unmasked areas
4996 R_Shadow_RenderMode_Lighting(true, false, false, false);
4998 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4999 for (i = 0;i < numlightentities;i++)
5000 R_Shadow_DrawEntityLight(lightentities[i]);
5002 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5003 if (r_shadow_usingdeferredprepass)
5004 R_Shadow_RenderMode_DrawDeferredLight(false);
5008 // draw lighting in the unmasked areas
5009 R_Shadow_RenderMode_Lighting(false, false, false, false);
5011 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5012 for (i = 0;i < numlightentities;i++)
5013 R_Shadow_DrawEntityLight(lightentities[i]);
5014 for (i = 0;i < numlightentities_noselfshadow;i++)
5015 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5017 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5018 if (r_shadow_usingdeferredprepass)
5019 R_Shadow_RenderMode_DrawDeferredLight(false);
5023 static void R_Shadow_FreeDeferred(void)
5025 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
5026 r_shadow_prepassgeometryfbo = 0;
5028 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
5029 r_shadow_prepasslightingdiffusespecularfbo = 0;
5031 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
5032 r_shadow_prepasslightingdiffusefbo = 0;
5034 if (r_shadow_prepassgeometrydepthbuffer)
5035 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
5036 r_shadow_prepassgeometrydepthbuffer = NULL;
5038 if (r_shadow_prepassgeometrynormalmaptexture)
5039 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
5040 r_shadow_prepassgeometrynormalmaptexture = NULL;
5042 if (r_shadow_prepasslightingdiffusetexture)
5043 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
5044 r_shadow_prepasslightingdiffusetexture = NULL;
5046 if (r_shadow_prepasslightingspeculartexture)
5047 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
5048 r_shadow_prepasslightingspeculartexture = NULL;
5051 void R_Shadow_DrawPrepass(void)
5055 entity_render_t *ent;
5056 float clearcolor[4];
5058 R_Mesh_ResetTextureState();
5060 GL_ColorMask(1,1,1,1);
5061 GL_BlendFunc(GL_ONE, GL_ZERO);
5064 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5065 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
5066 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
5067 if (r_timereport_active)
5068 R_TimeReport("prepasscleargeom");
5070 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
5071 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
5072 if (r_timereport_active)
5073 R_TimeReport("prepassworld");
5075 for (i = 0;i < r_refdef.scene.numentities;i++)
5077 if (!r_refdef.viewcache.entityvisible[i])
5079 ent = r_refdef.scene.entities[i];
5080 if (ent->model && ent->model->DrawPrepass != NULL)
5081 ent->model->DrawPrepass(ent);
5084 if (r_timereport_active)
5085 R_TimeReport("prepassmodels");
5087 GL_DepthMask(false);
5088 GL_ColorMask(1,1,1,1);
5091 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5092 Vector4Set(clearcolor, 0, 0, 0, 0);
5093 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
5094 if (r_timereport_active)
5095 R_TimeReport("prepassclearlit");
5097 R_Shadow_RenderMode_Begin();
5099 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5100 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5102 R_Shadow_RenderMode_End();
5104 if (r_timereport_active)
5105 R_TimeReport("prepasslights");
5108 #define MAX_SCENELIGHTS 65536
5109 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
5111 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
5113 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
5115 r_shadow_scenemaxlights *= 2;
5116 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
5117 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
5119 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
5123 void R_Shadow_DrawLightSprites(void);
5124 void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
5133 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
5134 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
5135 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
5137 if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
5138 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
5139 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
5140 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
5141 r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) ||
5142 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
5143 r_shadow_shadowmapborder != shadowmapborder ||
5144 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
5145 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
5146 R_Shadow_FreeShadowMaps();
5148 r_shadow_fb_fbo = fbo;
5149 r_shadow_fb_depthtexture = depthtexture;
5150 r_shadow_fb_colortexture = colortexture;
5152 r_shadow_usingshadowmaportho = false;
5154 switch (vid.renderpath)
5156 case RENDERPATH_GL20:
5157 case RENDERPATH_D3D9:
5158 case RENDERPATH_D3D10:
5159 case RENDERPATH_D3D11:
5160 case RENDERPATH_SOFT:
5162 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
5164 r_shadow_usingdeferredprepass = false;
5165 if (r_shadow_prepass_width)
5166 R_Shadow_FreeDeferred();
5167 r_shadow_prepass_width = r_shadow_prepass_height = 0;
5171 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
5173 R_Shadow_FreeDeferred();
5175 r_shadow_usingdeferredprepass = true;
5176 r_shadow_prepass_width = vid.width;
5177 r_shadow_prepass_height = vid.height;
5178 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
5179 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);
5180 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);
5181 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);
5183 // set up the geometry pass fbo (depth + normalmap)
5184 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5185 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5186 // render depth into a renderbuffer and other important properties into the normalmap texture
5188 // set up the lighting pass fbo (diffuse + specular)
5189 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5190 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5191 // render diffuse into one texture and specular into another,
5192 // with depth and normalmap bound as textures,
5193 // with depth bound as attachment as well
5195 // set up the lighting pass fbo (diffuse)
5196 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5197 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5198 // render diffuse into one texture,
5199 // with depth and normalmap bound as textures,
5200 // with depth bound as attachment as well
5204 case RENDERPATH_GL11:
5205 case RENDERPATH_GL13:
5206 case RENDERPATH_GLES1:
5207 case RENDERPATH_GLES2:
5208 r_shadow_usingdeferredprepass = false;
5212 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);
5214 r_shadow_scenenumlights = 0;
5215 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5216 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5217 for (lightindex = 0; lightindex < range; lightindex++)
5219 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5220 if (light && (light->flags & flag))
5222 R_Shadow_PrepareLight(&light->rtlight);
5223 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5226 if (r_refdef.scene.rtdlight)
5228 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5230 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
5231 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
5234 else if (gl_flashblend.integer)
5236 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5238 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
5239 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
5240 VectorScale(rtlight->color, f, rtlight->currentcolor);
5244 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
5245 if (r_shadow_debuglight.integer >= 0)
5247 r_shadow_scenenumlights = 0;
5248 lightindex = r_shadow_debuglight.integer;
5249 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5252 R_Shadow_PrepareLight(&light->rtlight);
5253 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5257 // if we're doing shadowmaps we need to prepare the atlas layout now
5258 if (R_Shadow_ShadowMappingEnabled())
5262 // allocate shadowmaps in the atlas now
5263 // 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...
5264 for (lod = 0; lod < 16; lod++)
5266 int packing_success = 0;
5267 int packing_failure = 0;
5268 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
5269 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
5270 if (r_shadow_shadowmapatlas_modelshadows_size)
5271 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);
5272 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5274 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
5275 int size = rtlight->shadowmapsidesize >> lod;
5277 if (!rtlight->castshadows)
5279 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
5282 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
5283 if (rtlight->cached_numshadowentities_noselfshadow)
5285 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
5287 rtlight->shadowmapatlassidesize = size;
5292 // note down that we failed to pack this one, it will have to disable shadows
5293 rtlight->shadowmapatlassidesize = 0;
5297 // generally everything fits and we stop here on the first iteration
5298 if (packing_failure == 0)
5303 if (r_editlights.integer)
5304 R_Shadow_DrawLightSprites();
5307 void R_Shadow_DrawShadowMaps(void)
5309 R_Shadow_RenderMode_Begin();
5310 R_Shadow_RenderMode_ActiveLight(NULL);
5312 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
5313 R_Shadow_ClearShadowMapTexture();
5315 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
5316 if (r_shadow_shadowmapatlas_modelshadows_size)
5318 R_Shadow_DrawModelShadowMaps();
5319 // don't let sound skip if going slow
5320 if (r_refdef.scene.extraupdate)
5324 if (R_Shadow_ShadowMappingEnabled())
5327 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5328 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
5331 R_Shadow_RenderMode_End();
5334 void R_Shadow_DrawLights(void)
5338 R_Shadow_RenderMode_Begin();
5340 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5341 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5343 R_Shadow_RenderMode_End();
5346 #define MAX_MODELSHADOWS 1024
5347 static int r_shadow_nummodelshadows;
5348 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
5350 void R_Shadow_PrepareModelShadows(void)
5353 float scale, size, radius, dot1, dot2;
5354 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5355 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
5356 entity_render_t *ent;
5358 r_shadow_nummodelshadows = 0;
5359 r_shadow_shadowmapatlas_modelshadows_size = 0;
5361 if (!r_refdef.scene.numentities || r_refdef.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
5364 switch (r_shadow_shadowmode)
5366 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
5367 if (r_shadows.integer >= 2)
5370 case R_SHADOW_SHADOWMODE_STENCIL:
5373 for (i = 0; i < r_refdef.scene.numentities; i++)
5375 ent = r_refdef.scene.entities[i];
5376 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5378 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5380 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5381 R_AnimCache_GetEntity(ent, false, false);
5389 size = 2 * r_shadow_shadowmapmaxsize;
5390 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
5391 radius = 0.5f * size / scale;
5393 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5394 VectorCopy(prvmshadowdir, shadowdir);
5395 VectorNormalize(shadowdir);
5396 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5397 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5398 if (fabs(dot1) <= fabs(dot2))
5399 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5401 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5402 VectorNormalize(shadowforward);
5403 CrossProduct(shadowdir, shadowforward, shadowright);
5404 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5405 VectorCopy(prvmshadowfocus, shadowfocus);
5406 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5407 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5408 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5409 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5410 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5412 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5414 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5415 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5416 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5417 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5418 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5419 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5421 for (i = 0; i < r_refdef.scene.numentities; i++)
5423 ent = r_refdef.scene.entities[i];
5424 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
5426 // cast shadows from anything of the map (submodels are optional)
5427 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5429 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5431 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5432 R_AnimCache_GetEntity(ent, false, false);
5436 if (r_shadow_nummodelshadows)
5438 r_shadow_shadowmapatlas_modelshadows_x = 0;
5439 r_shadow_shadowmapatlas_modelshadows_y = 0;
5440 r_shadow_shadowmapatlas_modelshadows_size = size;
5444 static void R_Shadow_DrawModelShadowMaps(void)
5447 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
5448 entity_render_t *ent;
5449 vec3_t relativelightorigin;
5450 vec3_t relativelightdirection, relativeforward, relativeright;
5451 vec3_t relativeshadowmins, relativeshadowmaxs;
5452 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
5453 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5455 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
5456 r_viewport_t viewport;
5458 size = r_shadow_shadowmapatlas_modelshadows_size;
5459 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
5460 radius = 0.5f / scale;
5461 nearclip = -r_shadows_throwdistance.value;
5462 farclip = r_shadows_throwdistance.value;
5463 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);
5465 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
5466 r_shadow_modelshadowmap_parameters[0] = size;
5467 r_shadow_modelshadowmap_parameters[1] = size;
5468 r_shadow_modelshadowmap_parameters[2] = 1.0;
5469 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
5470 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
5471 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
5472 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
5473 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
5474 r_shadow_usingshadowmaportho = true;
5476 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5477 VectorCopy(prvmshadowdir, shadowdir);
5478 VectorNormalize(shadowdir);
5479 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5480 VectorCopy(prvmshadowfocus, shadowfocus);
5481 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5482 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5483 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5484 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5485 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5486 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5487 if (fabs(dot1) <= fabs(dot2))
5488 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5490 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5491 VectorNormalize(shadowforward);
5492 VectorM(scale, shadowforward, &m[0]);
5493 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5495 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
5496 CrossProduct(shadowdir, shadowforward, shadowright);
5497 VectorM(scale, shadowright, &m[4]);
5498 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
5499 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
5500 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
5501 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
5502 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
5503 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);
5504 R_SetViewport(&viewport);
5506 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5508 // render into a slightly restricted region so that the borders of the
5509 // shadowmap area fade away, rather than streaking across everything
5510 // outside the usable area
5511 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
5513 for (i = 0;i < r_shadow_nummodelshadows;i++)
5515 ent = r_shadow_modelshadows[i];
5516 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5517 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
5518 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5519 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
5520 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
5521 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5522 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5523 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5524 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5525 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5526 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5527 RSurf_ActiveModelEntity(ent, false, false, false);
5528 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
5529 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5535 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
5537 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
5539 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
5540 Cvar_SetValueQuick(&r_test, 0);
5545 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
5546 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
5547 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
5548 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
5549 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
5550 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
5552 switch (vid.renderpath)
5554 case RENDERPATH_GL11:
5555 case RENDERPATH_GL13:
5556 case RENDERPATH_GL20:
5557 case RENDERPATH_SOFT:
5558 case RENDERPATH_GLES1:
5559 case RENDERPATH_GLES2:
5561 case RENDERPATH_D3D9:
5562 case RENDERPATH_D3D10:
5563 case RENDERPATH_D3D11:
5564 #ifdef MATRIX4x4_OPENGLORIENTATION
5565 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5566 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
5567 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
5568 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
5570 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5571 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
5572 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
5573 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
5579 void R_Shadow_DrawModelShadows(void)
5582 float relativethrowdistance;
5583 entity_render_t *ent;
5584 vec3_t relativelightorigin;
5585 vec3_t relativelightdirection;
5586 vec3_t relativeshadowmins, relativeshadowmaxs;
5587 vec3_t tmp, shadowdir;
5588 prvm_vec3_t prvmshadowdir;
5590 if (!r_shadow_nummodelshadows || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
5593 R_ResetViewRendering3D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5594 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
5595 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5596 R_Shadow_RenderMode_Begin();
5597 R_Shadow_RenderMode_ActiveLight(NULL);
5598 r_shadow_lightscissor[0] = r_refdef.view.x;
5599 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
5600 r_shadow_lightscissor[2] = r_refdef.view.width;
5601 r_shadow_lightscissor[3] = r_refdef.view.height;
5602 R_Shadow_RenderMode_StencilShadowVolumes(false);
5605 if (r_shadows.integer == 2)
5607 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5608 VectorCopy(prvmshadowdir, shadowdir);
5609 VectorNormalize(shadowdir);
5612 R_Shadow_ClearStencil();
5614 for (i = 0;i < r_shadow_nummodelshadows;i++)
5616 ent = r_shadow_modelshadows[i];
5618 // cast shadows from anything of the map (submodels are optional)
5619 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5620 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
5621 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
5622 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
5623 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5626 if(ent->entitynumber != 0)
5628 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
5630 // FIXME handle this
5631 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5635 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
5636 int entnum, entnum2, recursion;
5637 entnum = entnum2 = ent->entitynumber;
5638 for(recursion = 32; recursion > 0; --recursion)
5640 entnum2 = cl.entities[entnum].state_current.tagentity;
5641 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
5646 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
5648 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
5649 // transform into modelspace of OUR entity
5650 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
5651 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
5654 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5658 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5661 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
5662 RSurf_ActiveModelEntity(ent, false, false, false);
5663 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
5664 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5667 // not really the right mode, but this will disable any silly stencil features
5668 R_Shadow_RenderMode_End();
5670 // set up ortho view for rendering this pass
5671 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5672 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5673 //GL_ScissorTest(true);
5674 //R_EntityMatrix(&identitymatrix);
5675 //R_Mesh_ResetTextureState();
5676 R_ResetViewRendering2D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5678 // set up a darkening blend on shadowed areas
5679 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5680 //GL_DepthRange(0, 1);
5681 //GL_DepthTest(false);
5682 //GL_DepthMask(false);
5683 //GL_PolygonOffset(0, 0);CHECKGLERROR
5684 GL_Color(0, 0, 0, r_shadows_darken.value);
5685 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5686 //GL_DepthFunc(GL_ALWAYS);
5687 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5689 // apply the blend to the shadowed areas
5690 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5691 R_SetupShader_Generic_NoTexture(false, true);
5692 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5694 // restore the viewport
5695 R_SetViewport(&r_refdef.view.viewport);
5697 // restore other state to normal
5698 //R_Shadow_RenderMode_End();
5701 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5704 vec3_t centerorigin;
5705 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5708 // if it's too close, skip it
5709 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5711 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5714 if (usequery && r_numqueries + 2 <= r_maxqueries)
5716 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5717 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5718 // 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
5719 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5721 switch(vid.renderpath)
5723 case RENDERPATH_GL11:
5724 case RENDERPATH_GL13:
5725 case RENDERPATH_GL20:
5726 case RENDERPATH_GLES1:
5727 case RENDERPATH_GLES2:
5728 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5730 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5731 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5732 GL_DepthFunc(GL_ALWAYS);
5733 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5734 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5735 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5736 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5737 GL_DepthFunc(GL_LEQUAL);
5738 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5739 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5740 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5741 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5742 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5746 case RENDERPATH_D3D9:
5747 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5749 case RENDERPATH_D3D10:
5750 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5752 case RENDERPATH_D3D11:
5753 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5755 case RENDERPATH_SOFT:
5756 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5760 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5763 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5765 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5768 unsigned int occlude = 0;
5769 GLint allpixels = 0, visiblepixels = 0;
5771 // now we have to check the query result
5772 if (rtlight->corona_queryindex_visiblepixels)
5774 switch(vid.renderpath)
5776 case RENDERPATH_GL11:
5777 case RENDERPATH_GL13:
5778 case RENDERPATH_GL20:
5779 case RENDERPATH_GLES1:
5780 case RENDERPATH_GLES2:
5781 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5783 // See if we can use the GPU-side method to prevent implicit sync
5784 if (vid.support.arb_query_buffer_object) {
5785 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
5786 if (!r_shadow_occlusion_buf) {
5787 qglGenBuffersARB(1, &r_shadow_occlusion_buf);
5788 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5789 qglBufferDataARB(GL_QUERY_BUFFER_ARB, 8, NULL, GL_DYNAMIC_COPY);
5791 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5793 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(0));
5794 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4));
5795 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
5796 occlude = MATERIALFLAG_OCCLUDE;
5798 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5799 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5800 if (visiblepixels < 1 || allpixels < 1)
5802 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5804 cscale *= rtlight->corona_visibility;
5810 case RENDERPATH_D3D9:
5811 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5813 case RENDERPATH_D3D10:
5814 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5816 case RENDERPATH_D3D11:
5817 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5819 case RENDERPATH_SOFT:
5820 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5828 // FIXME: these traces should scan all render entities instead of cl.world
5829 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)
5832 VectorScale(rtlight->currentcolor, cscale, color);
5833 if (VectorLength(color) > (1.0f / 256.0f))
5836 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
5839 VectorNegate(color, color);
5840 GL_BlendEquationSubtract(true);
5842 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5843 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);
5844 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
5846 GL_BlendEquationSubtract(false);
5850 void R_Shadow_DrawCoronas(void)
5853 qboolean usequery = false;
5858 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
5860 if (r_fb.water.renderingscene)
5862 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5863 R_EntityMatrix(&identitymatrix);
5865 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5867 // check occlusion of coronas
5868 // use GL_ARB_occlusion_query if available
5869 // otherwise use raytraces
5871 switch (vid.renderpath)
5873 case RENDERPATH_GL11:
5874 case RENDERPATH_GL13:
5875 case RENDERPATH_GL20:
5876 case RENDERPATH_GLES1:
5877 case RENDERPATH_GLES2:
5878 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
5879 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5882 GL_ColorMask(0,0,0,0);
5883 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
5884 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
5887 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
5888 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
5890 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
5893 RSurf_ActiveWorldEntity();
5894 GL_BlendFunc(GL_ONE, GL_ZERO);
5895 GL_CullFace(GL_NONE);
5896 GL_DepthMask(false);
5897 GL_DepthRange(0, 1);
5898 GL_PolygonOffset(0, 0);
5900 R_Mesh_ResetTextureState();
5901 R_SetupShader_Generic_NoTexture(false, false);
5905 case RENDERPATH_D3D9:
5907 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5909 case RENDERPATH_D3D10:
5910 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5912 case RENDERPATH_D3D11:
5913 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5915 case RENDERPATH_SOFT:
5917 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5920 for (lightindex = 0;lightindex < range;lightindex++)
5922 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5925 rtlight = &light->rtlight;
5926 rtlight->corona_visibility = 0;
5927 rtlight->corona_queryindex_visiblepixels = 0;
5928 rtlight->corona_queryindex_allpixels = 0;
5929 if (!(rtlight->flags & flag))
5931 if (rtlight->corona <= 0)
5933 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
5935 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5937 for (i = 0;i < r_refdef.scene.numlights;i++)
5939 rtlight = r_refdef.scene.lights[i];
5940 rtlight->corona_visibility = 0;
5941 rtlight->corona_queryindex_visiblepixels = 0;
5942 rtlight->corona_queryindex_allpixels = 0;
5943 if (!(rtlight->flags & flag))
5945 if (rtlight->corona <= 0)
5947 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5950 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5952 // now draw the coronas using the query data for intensity info
5953 for (lightindex = 0;lightindex < range;lightindex++)
5955 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5958 rtlight = &light->rtlight;
5959 if (rtlight->corona_visibility <= 0)
5961 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5963 for (i = 0;i < r_refdef.scene.numlights;i++)
5965 rtlight = r_refdef.scene.lights[i];
5966 if (rtlight->corona_visibility <= 0)
5968 if (gl_flashblend.integer)
5969 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
5971 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5977 static dlight_t *R_Shadow_NewWorldLight(void)
5979 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
5982 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)
5986 // 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
5988 // validate parameters
5992 // copy to light properties
5993 VectorCopy(origin, light->origin);
5994 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
5995 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
5996 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
5998 light->color[0] = max(color[0], 0);
5999 light->color[1] = max(color[1], 0);
6000 light->color[2] = max(color[2], 0);
6002 light->color[0] = color[0];
6003 light->color[1] = color[1];
6004 light->color[2] = color[2];
6005 light->radius = max(radius, 0);
6006 light->style = style;
6007 light->shadow = shadowenable;
6008 light->corona = corona;
6009 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
6010 light->coronasizescale = coronasizescale;
6011 light->ambientscale = ambientscale;
6012 light->diffusescale = diffusescale;
6013 light->specularscale = specularscale;
6014 light->flags = flags;
6016 // update renderable light data
6017 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
6018 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);
6021 static void R_Shadow_FreeWorldLight(dlight_t *light)
6023 if (r_shadow_selectedlight == light)
6024 r_shadow_selectedlight = NULL;
6025 R_RTLight_Uncompile(&light->rtlight);
6026 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
6029 void R_Shadow_ClearWorldLights(void)
6033 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6034 for (lightindex = 0;lightindex < range;lightindex++)
6036 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6038 R_Shadow_FreeWorldLight(light);
6040 r_shadow_selectedlight = NULL;
6043 static void R_Shadow_SelectLight(dlight_t *light)
6045 if (r_shadow_selectedlight)
6046 r_shadow_selectedlight->selected = false;
6047 r_shadow_selectedlight = light;
6048 if (r_shadow_selectedlight)
6049 r_shadow_selectedlight->selected = true;
6052 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6054 // this is never batched (there can be only one)
6056 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
6057 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6058 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6061 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6066 skinframe_t *skinframe;
6069 // this is never batched (due to the ent parameter changing every time)
6070 // so numsurfaces == 1 and surfacelist[0] == lightnumber
6071 const dlight_t *light = (dlight_t *)ent;
6074 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
6077 VectorScale(light->color, intensity, spritecolor);
6078 if (VectorLength(spritecolor) < 0.1732f)
6079 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
6080 if (VectorLength(spritecolor) > 1.0f)
6081 VectorNormalize(spritecolor);
6083 // draw light sprite
6084 if (light->cubemapname[0] && !light->shadow)
6085 skinframe = r_editlights_sprcubemapnoshadowlight;
6086 else if (light->cubemapname[0])
6087 skinframe = r_editlights_sprcubemaplight;
6088 else if (!light->shadow)
6089 skinframe = r_editlights_sprnoshadowlight;
6091 skinframe = r_editlights_sprlight;
6093 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);
6094 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6096 // draw selection sprite if light is selected
6097 if (light->selected)
6099 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6100 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6101 // VorteX todo: add normalmode/realtime mode light overlay sprites?
6105 void R_Shadow_DrawLightSprites(void)
6109 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6110 for (lightindex = 0;lightindex < range;lightindex++)
6112 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6114 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
6116 if (!r_editlights_lockcursor)
6117 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
6120 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
6125 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6126 if (lightindex >= range)
6128 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6131 rtlight = &light->rtlight;
6132 //if (!(rtlight->flags & flag))
6134 VectorCopy(rtlight->shadoworigin, origin);
6135 *radius = rtlight->radius;
6136 VectorCopy(rtlight->color, color);
6140 static void R_Shadow_SelectLightInView(void)
6142 float bestrating, rating, temp[3];
6146 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6150 if (r_editlights_lockcursor)
6152 for (lightindex = 0;lightindex < range;lightindex++)
6154 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6157 VectorSubtract(light->origin, r_refdef.view.origin, temp);
6158 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
6161 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
6162 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)
6164 bestrating = rating;
6169 R_Shadow_SelectLight(best);
6172 void R_Shadow_LoadWorldLights(void)
6174 int n, a, style, shadow, flags;
6175 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
6176 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
6177 if (cl.worldmodel == NULL)
6179 Con_Print("No map loaded.\n");
6182 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6183 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6193 for (;COM_Parse(t, true) && strcmp(
6194 if (COM_Parse(t, true))
6196 if (com_token[0] == '!')
6199 origin[0] = atof(com_token+1);
6202 origin[0] = atof(com_token);
6207 while (*s && *s != '\n' && *s != '\r')
6213 // check for modifier flags
6220 #if _MSC_VER >= 1400
6221 #define sscanf sscanf_s
6223 cubemapname[sizeof(cubemapname)-1] = 0;
6224 #if MAX_QPATH != 128
6225 #error update this code if MAX_QPATH changes
6227 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
6228 #if _MSC_VER >= 1400
6229 , sizeof(cubemapname)
6231 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
6234 flags = LIGHTFLAG_REALTIMEMODE;
6242 coronasizescale = 0.25f;
6244 VectorClear(angles);
6247 if (a < 9 || !strcmp(cubemapname, "\"\""))
6249 // remove quotes on cubemapname
6250 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
6253 namelen = strlen(cubemapname) - 2;
6254 memmove(cubemapname, cubemapname + 1, namelen);
6255 cubemapname[namelen] = '\0';
6259 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);
6262 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6270 Con_Printf("invalid rtlights file \"%s\"\n", name);
6271 Mem_Free(lightsstring);
6275 void R_Shadow_SaveWorldLights(void)
6279 size_t bufchars, bufmaxchars;
6281 char name[MAX_QPATH];
6282 char line[MAX_INPUTLINE];
6283 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
6284 // I hate lines which are 3 times my screen size :( --blub
6287 if (cl.worldmodel == NULL)
6289 Con_Print("No map loaded.\n");
6292 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6293 bufchars = bufmaxchars = 0;
6295 for (lightindex = 0;lightindex < range;lightindex++)
6297 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6300 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
6301 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);
6302 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
6303 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]);
6305 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);
6306 if (bufchars + strlen(line) > bufmaxchars)
6308 bufmaxchars = bufchars + strlen(line) + 2048;
6310 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
6314 memcpy(buf, oldbuf, bufchars);
6320 memcpy(buf + bufchars, line, strlen(line));
6321 bufchars += strlen(line);
6325 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
6330 void R_Shadow_LoadLightsFile(void)
6333 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
6334 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
6335 if (cl.worldmodel == NULL)
6337 Con_Print("No map loaded.\n");
6340 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
6341 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6349 while (*s && *s != '\n' && *s != '\r')
6355 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);
6359 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);
6362 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
6363 radius = bound(15, radius, 4096);
6364 VectorScale(color, (2.0f / (8388608.0f)), color);
6365 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6373 Con_Printf("invalid lights file \"%s\"\n", name);
6374 Mem_Free(lightsstring);
6378 // tyrlite/hmap2 light types in the delay field
6379 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
6381 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
6393 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
6394 char key[256], value[MAX_INPUTLINE];
6397 if (cl.worldmodel == NULL)
6399 Con_Print("No map loaded.\n");
6402 // try to load a .ent file first
6403 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
6404 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
6405 // and if that is not found, fall back to the bsp file entity string
6407 data = cl.worldmodel->brush.entities;
6410 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
6412 type = LIGHTTYPE_MINUSX;
6413 origin[0] = origin[1] = origin[2] = 0;
6414 originhack[0] = originhack[1] = originhack[2] = 0;
6415 angles[0] = angles[1] = angles[2] = 0;
6416 color[0] = color[1] = color[2] = 1;
6417 light[0] = light[1] = light[2] = 1;light[3] = 300;
6418 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
6428 if (!COM_ParseToken_Simple(&data, false, false, true))
6430 if (com_token[0] == '}')
6431 break; // end of entity
6432 if (com_token[0] == '_')
6433 strlcpy(key, com_token + 1, sizeof(key));
6435 strlcpy(key, com_token, sizeof(key));
6436 while (key[strlen(key)-1] == ' ') // remove trailing spaces
6437 key[strlen(key)-1] = 0;
6438 if (!COM_ParseToken_Simple(&data, false, false, true))
6440 strlcpy(value, com_token, sizeof(value));
6442 // now that we have the key pair worked out...
6443 if (!strcmp("light", key))
6445 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
6449 light[0] = vec[0] * (1.0f / 256.0f);
6450 light[1] = vec[0] * (1.0f / 256.0f);
6451 light[2] = vec[0] * (1.0f / 256.0f);
6457 light[0] = vec[0] * (1.0f / 255.0f);
6458 light[1] = vec[1] * (1.0f / 255.0f);
6459 light[2] = vec[2] * (1.0f / 255.0f);
6463 else if (!strcmp("delay", key))
6465 else if (!strcmp("origin", key))
6466 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
6467 else if (!strcmp("angle", key))
6468 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
6469 else if (!strcmp("angles", key))
6470 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
6471 else if (!strcmp("color", key))
6472 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
6473 else if (!strcmp("wait", key))
6474 fadescale = atof(value);
6475 else if (!strcmp("classname", key))
6477 if (!strncmp(value, "light", 5))
6480 if (!strcmp(value, "light_fluoro"))
6485 overridecolor[0] = 1;
6486 overridecolor[1] = 1;
6487 overridecolor[2] = 1;
6489 if (!strcmp(value, "light_fluorospark"))
6494 overridecolor[0] = 1;
6495 overridecolor[1] = 1;
6496 overridecolor[2] = 1;
6498 if (!strcmp(value, "light_globe"))
6503 overridecolor[0] = 1;
6504 overridecolor[1] = 0.8;
6505 overridecolor[2] = 0.4;
6507 if (!strcmp(value, "light_flame_large_yellow"))
6512 overridecolor[0] = 1;
6513 overridecolor[1] = 0.5;
6514 overridecolor[2] = 0.1;
6516 if (!strcmp(value, "light_flame_small_yellow"))
6521 overridecolor[0] = 1;
6522 overridecolor[1] = 0.5;
6523 overridecolor[2] = 0.1;
6525 if (!strcmp(value, "light_torch_small_white"))
6530 overridecolor[0] = 1;
6531 overridecolor[1] = 0.5;
6532 overridecolor[2] = 0.1;
6534 if (!strcmp(value, "light_torch_small_walltorch"))
6539 overridecolor[0] = 1;
6540 overridecolor[1] = 0.5;
6541 overridecolor[2] = 0.1;
6545 else if (!strcmp("style", key))
6546 style = atoi(value);
6547 else if (!strcmp("skin", key))
6548 skin = (int)atof(value);
6549 else if (!strcmp("pflags", key))
6550 pflags = (int)atof(value);
6551 //else if (!strcmp("effects", key))
6552 // effects = (int)atof(value);
6553 else if (cl.worldmodel->type == mod_brushq3)
6555 if (!strcmp("scale", key))
6556 lightscale = atof(value);
6557 if (!strcmp("fade", key))
6558 fadescale = atof(value);
6563 if (lightscale <= 0)
6567 if (color[0] == color[1] && color[0] == color[2])
6569 color[0] *= overridecolor[0];
6570 color[1] *= overridecolor[1];
6571 color[2] *= overridecolor[2];
6573 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
6574 color[0] = color[0] * light[0];
6575 color[1] = color[1] * light[1];
6576 color[2] = color[2] * light[2];
6579 case LIGHTTYPE_MINUSX:
6581 case LIGHTTYPE_RECIPX:
6583 VectorScale(color, (1.0f / 16.0f), color);
6585 case LIGHTTYPE_RECIPXX:
6587 VectorScale(color, (1.0f / 16.0f), color);
6590 case LIGHTTYPE_NONE:
6594 case LIGHTTYPE_MINUSXX:
6597 VectorAdd(origin, originhack, origin);
6599 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);
6602 Mem_Free(entfiledata);
6606 static void R_Shadow_SetCursorLocationForView(void)
6609 vec3_t dest, endpos;
6611 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
6612 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true);
6613 if (trace.fraction < 1)
6615 dist = trace.fraction * r_editlights_cursordistance.value;
6616 push = r_editlights_cursorpushback.value;
6620 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
6621 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
6625 VectorClear( endpos );
6627 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6628 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6629 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6632 void R_Shadow_UpdateWorldLightSelection(void)
6634 if (r_editlights.integer)
6636 R_Shadow_SetCursorLocationForView();
6637 R_Shadow_SelectLightInView();
6640 R_Shadow_SelectLight(NULL);
6643 static void R_Shadow_EditLights_Clear_f(void)
6645 R_Shadow_ClearWorldLights();
6648 void R_Shadow_EditLights_Reload_f(void)
6652 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
6653 R_Shadow_ClearWorldLights();
6654 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
6656 R_Shadow_LoadWorldLights();
6657 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6658 R_Shadow_LoadLightsFile();
6660 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
6662 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6663 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6667 static void R_Shadow_EditLights_Save_f(void)
6671 R_Shadow_SaveWorldLights();
6674 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6676 R_Shadow_ClearWorldLights();
6677 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6680 static void R_Shadow_EditLights_ImportLightsFile_f(void)
6682 R_Shadow_ClearWorldLights();
6683 R_Shadow_LoadLightsFile();
6686 static void R_Shadow_EditLights_Spawn_f(void)
6689 if (!r_editlights.integer)
6691 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6694 if (Cmd_Argc() != 1)
6696 Con_Print("r_editlights_spawn does not take parameters\n");
6699 color[0] = color[1] = color[2] = 1;
6700 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6703 static void R_Shadow_EditLights_Edit_f(void)
6705 vec3_t origin, angles, color;
6706 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6707 int style, shadows, flags, normalmode, realtimemode;
6708 char cubemapname[MAX_INPUTLINE];
6709 if (!r_editlights.integer)
6711 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6714 if (!r_shadow_selectedlight)
6716 Con_Print("No selected light.\n");
6719 VectorCopy(r_shadow_selectedlight->origin, origin);
6720 VectorCopy(r_shadow_selectedlight->angles, angles);
6721 VectorCopy(r_shadow_selectedlight->color, color);
6722 radius = r_shadow_selectedlight->radius;
6723 style = r_shadow_selectedlight->style;
6724 if (r_shadow_selectedlight->cubemapname)
6725 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6728 shadows = r_shadow_selectedlight->shadow;
6729 corona = r_shadow_selectedlight->corona;
6730 coronasizescale = r_shadow_selectedlight->coronasizescale;
6731 ambientscale = r_shadow_selectedlight->ambientscale;
6732 diffusescale = r_shadow_selectedlight->diffusescale;
6733 specularscale = r_shadow_selectedlight->specularscale;
6734 flags = r_shadow_selectedlight->flags;
6735 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6736 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6737 if (!strcmp(Cmd_Argv(1), "origin"))
6739 if (Cmd_Argc() != 5)
6741 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6744 origin[0] = atof(Cmd_Argv(2));
6745 origin[1] = atof(Cmd_Argv(3));
6746 origin[2] = atof(Cmd_Argv(4));
6748 else if (!strcmp(Cmd_Argv(1), "originscale"))
6750 if (Cmd_Argc() != 5)
6752 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6755 origin[0] *= atof(Cmd_Argv(2));
6756 origin[1] *= atof(Cmd_Argv(3));
6757 origin[2] *= atof(Cmd_Argv(4));
6759 else if (!strcmp(Cmd_Argv(1), "originx"))
6761 if (Cmd_Argc() != 3)
6763 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6766 origin[0] = atof(Cmd_Argv(2));
6768 else if (!strcmp(Cmd_Argv(1), "originy"))
6770 if (Cmd_Argc() != 3)
6772 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6775 origin[1] = atof(Cmd_Argv(2));
6777 else if (!strcmp(Cmd_Argv(1), "originz"))
6779 if (Cmd_Argc() != 3)
6781 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6784 origin[2] = atof(Cmd_Argv(2));
6786 else if (!strcmp(Cmd_Argv(1), "move"))
6788 if (Cmd_Argc() != 5)
6790 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6793 origin[0] += atof(Cmd_Argv(2));
6794 origin[1] += atof(Cmd_Argv(3));
6795 origin[2] += atof(Cmd_Argv(4));
6797 else if (!strcmp(Cmd_Argv(1), "movex"))
6799 if (Cmd_Argc() != 3)
6801 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6804 origin[0] += atof(Cmd_Argv(2));
6806 else if (!strcmp(Cmd_Argv(1), "movey"))
6808 if (Cmd_Argc() != 3)
6810 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6813 origin[1] += atof(Cmd_Argv(2));
6815 else if (!strcmp(Cmd_Argv(1), "movez"))
6817 if (Cmd_Argc() != 3)
6819 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6822 origin[2] += atof(Cmd_Argv(2));
6824 else if (!strcmp(Cmd_Argv(1), "angles"))
6826 if (Cmd_Argc() != 5)
6828 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6831 angles[0] = atof(Cmd_Argv(2));
6832 angles[1] = atof(Cmd_Argv(3));
6833 angles[2] = atof(Cmd_Argv(4));
6835 else if (!strcmp(Cmd_Argv(1), "anglesx"))
6837 if (Cmd_Argc() != 3)
6839 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6842 angles[0] = atof(Cmd_Argv(2));
6844 else if (!strcmp(Cmd_Argv(1), "anglesy"))
6846 if (Cmd_Argc() != 3)
6848 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6851 angles[1] = atof(Cmd_Argv(2));
6853 else if (!strcmp(Cmd_Argv(1), "anglesz"))
6855 if (Cmd_Argc() != 3)
6857 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6860 angles[2] = atof(Cmd_Argv(2));
6862 else if (!strcmp(Cmd_Argv(1), "color"))
6864 if (Cmd_Argc() != 5)
6866 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
6869 color[0] = atof(Cmd_Argv(2));
6870 color[1] = atof(Cmd_Argv(3));
6871 color[2] = atof(Cmd_Argv(4));
6873 else if (!strcmp(Cmd_Argv(1), "radius"))
6875 if (Cmd_Argc() != 3)
6877 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6880 radius = atof(Cmd_Argv(2));
6882 else if (!strcmp(Cmd_Argv(1), "colorscale"))
6884 if (Cmd_Argc() == 3)
6886 double scale = atof(Cmd_Argv(2));
6893 if (Cmd_Argc() != 5)
6895 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
6898 color[0] *= atof(Cmd_Argv(2));
6899 color[1] *= atof(Cmd_Argv(3));
6900 color[2] *= atof(Cmd_Argv(4));
6903 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
6905 if (Cmd_Argc() != 3)
6907 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6910 radius *= atof(Cmd_Argv(2));
6912 else if (!strcmp(Cmd_Argv(1), "style"))
6914 if (Cmd_Argc() != 3)
6916 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6919 style = atoi(Cmd_Argv(2));
6921 else if (!strcmp(Cmd_Argv(1), "cubemap"))
6925 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6928 if (Cmd_Argc() == 3)
6929 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
6933 else if (!strcmp(Cmd_Argv(1), "shadows"))
6935 if (Cmd_Argc() != 3)
6937 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6940 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6942 else if (!strcmp(Cmd_Argv(1), "corona"))
6944 if (Cmd_Argc() != 3)
6946 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6949 corona = atof(Cmd_Argv(2));
6951 else if (!strcmp(Cmd_Argv(1), "coronasize"))
6953 if (Cmd_Argc() != 3)
6955 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6958 coronasizescale = atof(Cmd_Argv(2));
6960 else if (!strcmp(Cmd_Argv(1), "ambient"))
6962 if (Cmd_Argc() != 3)
6964 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6967 ambientscale = atof(Cmd_Argv(2));
6969 else if (!strcmp(Cmd_Argv(1), "diffuse"))
6971 if (Cmd_Argc() != 3)
6973 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6976 diffusescale = atof(Cmd_Argv(2));
6978 else if (!strcmp(Cmd_Argv(1), "specular"))
6980 if (Cmd_Argc() != 3)
6982 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6985 specularscale = atof(Cmd_Argv(2));
6987 else if (!strcmp(Cmd_Argv(1), "normalmode"))
6989 if (Cmd_Argc() != 3)
6991 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6994 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6996 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
6998 if (Cmd_Argc() != 3)
7000 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7003 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7007 Con_Print("usage: r_editlights_edit [property] [value]\n");
7008 Con_Print("Selected light's properties:\n");
7009 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7010 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7011 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7012 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
7013 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
7014 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
7015 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
7016 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
7017 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
7018 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
7019 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
7020 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
7021 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
7022 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
7025 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
7026 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
7029 static void R_Shadow_EditLights_EditAll_f(void)
7032 dlight_t *light, *oldselected;
7035 if (!r_editlights.integer)
7037 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
7041 oldselected = r_shadow_selectedlight;
7042 // EditLights doesn't seem to have a "remove" command or something so:
7043 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7044 for (lightindex = 0;lightindex < range;lightindex++)
7046 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7049 R_Shadow_SelectLight(light);
7050 R_Shadow_EditLights_Edit_f();
7052 // return to old selected (to not mess editing once selection is locked)
7053 R_Shadow_SelectLight(oldselected);
7056 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
7058 int lightnumber, lightcount;
7059 size_t lightindex, range;
7064 if (!r_editlights.integer)
7067 // update cvars so QC can query them
7068 if (r_shadow_selectedlight)
7070 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7071 Cvar_SetQuick(&r_editlights_current_origin, temp);
7072 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7073 Cvar_SetQuick(&r_editlights_current_angles, temp);
7074 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7075 Cvar_SetQuick(&r_editlights_current_color, temp);
7076 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
7077 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
7078 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
7079 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
7080 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
7081 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
7082 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
7083 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
7084 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
7085 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
7086 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
7089 // draw properties on screen
7090 if (!r_editlights_drawproperties.integer)
7092 x = vid_conwidth.value - 240;
7094 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
7097 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7098 for (lightindex = 0;lightindex < range;lightindex++)
7100 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7103 if (light == r_shadow_selectedlight)
7104 lightnumber = (int)lightindex;
7107 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;
7108 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;
7110 if (r_shadow_selectedlight == NULL)
7112 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;
7113 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;
7114 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;
7115 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;
7116 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;
7117 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;
7118 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;
7119 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;
7120 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;
7121 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;
7122 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;
7123 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;
7124 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;
7125 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;
7126 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;
7129 static void R_Shadow_EditLights_ToggleShadow_f(void)
7131 if (!r_editlights.integer)
7133 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7136 if (!r_shadow_selectedlight)
7138 Con_Print("No selected light.\n");
7141 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);
7144 static void R_Shadow_EditLights_ToggleCorona_f(void)
7146 if (!r_editlights.integer)
7148 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7151 if (!r_shadow_selectedlight)
7153 Con_Print("No selected light.\n");
7156 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);
7159 static void R_Shadow_EditLights_Remove_f(void)
7161 if (!r_editlights.integer)
7163 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
7166 if (!r_shadow_selectedlight)
7168 Con_Print("No selected light.\n");
7171 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
7172 r_shadow_selectedlight = NULL;
7175 static void R_Shadow_EditLights_Help_f(void)
7178 "Documentation on r_editlights system:\n"
7180 "r_editlights : enable/disable editing mode\n"
7181 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
7182 "r_editlights_cursorpushback : push back cursor this far from surface\n"
7183 "r_editlights_cursorpushoff : push cursor off surface this far\n"
7184 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
7185 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
7187 "r_editlights_help : this help\n"
7188 "r_editlights_clear : remove all lights\n"
7189 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
7190 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
7191 "r_editlights_save : save to .rtlights file\n"
7192 "r_editlights_spawn : create a light with default settings\n"
7193 "r_editlights_edit command : edit selected light - more documentation below\n"
7194 "r_editlights_remove : remove selected light\n"
7195 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
7196 "r_editlights_importlightentitiesfrommap : reload light entities\n"
7197 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
7199 "origin x y z : set light location\n"
7200 "originx x: set x component of light location\n"
7201 "originy y: set y component of light location\n"
7202 "originz z: set z component of light location\n"
7203 "move x y z : adjust light location\n"
7204 "movex x: adjust x component of light location\n"
7205 "movey y: adjust y component of light location\n"
7206 "movez z: adjust z component of light location\n"
7207 "angles x y z : set light angles\n"
7208 "anglesx x: set x component of light angles\n"
7209 "anglesy y: set y component of light angles\n"
7210 "anglesz z: set z component of light angles\n"
7211 "color r g b : set color of light (can be brighter than 1 1 1)\n"
7212 "radius radius : set radius (size) of light\n"
7213 "colorscale grey : multiply color of light (1 does nothing)\n"
7214 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
7215 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
7216 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
7217 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
7218 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
7219 "cubemap basename : set filter cubemap of light\n"
7220 "shadows 1/0 : turn on/off shadows\n"
7221 "corona n : set corona intensity\n"
7222 "coronasize n : set corona size (0-1)\n"
7223 "ambient n : set ambient intensity (0-1)\n"
7224 "diffuse n : set diffuse intensity (0-1)\n"
7225 "specular n : set specular intensity (0-1)\n"
7226 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
7227 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
7228 "<nothing> : print light properties to console\n"
7232 static void R_Shadow_EditLights_CopyInfo_f(void)
7234 if (!r_editlights.integer)
7236 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
7239 if (!r_shadow_selectedlight)
7241 Con_Print("No selected light.\n");
7244 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
7245 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
7246 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
7247 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
7248 if (r_shadow_selectedlight->cubemapname)
7249 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
7251 r_shadow_bufferlight.cubemapname[0] = 0;
7252 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
7253 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
7254 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
7255 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
7256 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
7257 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
7258 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
7261 static void R_Shadow_EditLights_PasteInfo_f(void)
7263 if (!r_editlights.integer)
7265 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
7268 if (!r_shadow_selectedlight)
7270 Con_Print("No selected light.\n");
7273 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);
7276 static void R_Shadow_EditLights_Lock_f(void)
7278 if (!r_editlights.integer)
7280 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
7283 if (r_editlights_lockcursor)
7285 r_editlights_lockcursor = false;
7288 if (!r_shadow_selectedlight)
7290 Con_Print("No selected light to lock on.\n");
7293 r_editlights_lockcursor = true;
7296 static void R_Shadow_EditLights_Init(void)
7298 Cvar_RegisterVariable(&r_editlights);
7299 Cvar_RegisterVariable(&r_editlights_cursordistance);
7300 Cvar_RegisterVariable(&r_editlights_cursorpushback);
7301 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
7302 Cvar_RegisterVariable(&r_editlights_cursorgrid);
7303 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
7304 Cvar_RegisterVariable(&r_editlights_drawproperties);
7305 Cvar_RegisterVariable(&r_editlights_current_origin);
7306 Cvar_RegisterVariable(&r_editlights_current_angles);
7307 Cvar_RegisterVariable(&r_editlights_current_color);
7308 Cvar_RegisterVariable(&r_editlights_current_radius);
7309 Cvar_RegisterVariable(&r_editlights_current_corona);
7310 Cvar_RegisterVariable(&r_editlights_current_coronasize);
7311 Cvar_RegisterVariable(&r_editlights_current_style);
7312 Cvar_RegisterVariable(&r_editlights_current_shadows);
7313 Cvar_RegisterVariable(&r_editlights_current_cubemap);
7314 Cvar_RegisterVariable(&r_editlights_current_ambient);
7315 Cvar_RegisterVariable(&r_editlights_current_diffuse);
7316 Cvar_RegisterVariable(&r_editlights_current_specular);
7317 Cvar_RegisterVariable(&r_editlights_current_normalmode);
7318 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
7319 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
7320 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
7321 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)");
7322 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
7323 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
7324 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
7325 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)");
7326 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
7327 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
7328 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
7329 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
7330 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
7331 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
7332 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)");
7333 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
7339 =============================================================================
7343 =============================================================================
7346 void R_LightPoint(float *color, const vec3_t p, const int flags)
7348 int i, numlights, flag;
7349 float f, relativepoint[3], dist, dist2, lightradius2;
7354 if (r_fullbright.integer)
7356 VectorSet(color, 1, 1, 1);
7362 if (flags & LP_LIGHTMAP)
7364 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7366 VectorClear(diffuse);
7367 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, color, diffuse, n);
7368 VectorAdd(color, diffuse, color);
7371 VectorSet(color, 1, 1, 1);
7372 color[0] += r_refdef.scene.ambient;
7373 color[1] += r_refdef.scene.ambient;
7374 color[2] += r_refdef.scene.ambient;
7377 if (flags & LP_RTWORLD)
7379 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7380 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7381 for (i = 0; i < numlights; i++)
7383 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7386 light = &dlight->rtlight;
7387 if (!(light->flags & flag))
7390 lightradius2 = light->radius * light->radius;
7391 VectorSubtract(light->shadoworigin, p, relativepoint);
7392 dist2 = VectorLength2(relativepoint);
7393 if (dist2 >= lightradius2)
7395 dist = sqrt(dist2) / light->radius;
7396 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7399 // todo: add to both ambient and diffuse
7400 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)
7401 VectorMA(color, f, light->currentcolor, color);
7404 if (flags & LP_DYNLIGHT)
7407 for (i = 0;i < r_refdef.scene.numlights;i++)
7409 light = r_refdef.scene.lights[i];
7411 lightradius2 = light->radius * light->radius;
7412 VectorSubtract(light->shadoworigin, p, relativepoint);
7413 dist2 = VectorLength2(relativepoint);
7414 if (dist2 >= lightradius2)
7416 dist = sqrt(dist2) / light->radius;
7417 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7420 // todo: add to both ambient and diffuse
7421 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)
7422 VectorMA(color, f, light->color, color);
7427 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
7429 int i, numlights, flag;
7432 float relativepoint[3];
7441 if (r_fullbright.integer)
7443 VectorSet(ambient, 1, 1, 1);
7444 VectorClear(diffuse);
7445 VectorClear(lightdir);
7449 if (flags == LP_LIGHTMAP)
7451 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7452 VectorClear(diffuse);
7453 VectorClear(lightdir);
7454 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7455 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
7457 VectorSet(ambient, 1, 1, 1);
7461 memset(sample, 0, sizeof(sample));
7462 VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7464 if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7467 VectorClear(tempambient);
7469 VectorClear(relativepoint);
7470 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
7471 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
7472 VectorScale(color, r_refdef.lightmapintensity, color);
7473 VectorAdd(sample, tempambient, sample);
7474 VectorMA(sample , 0.5f , color, sample );
7475 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7476 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7477 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7478 // calculate a weighted average light direction as well
7479 intensity = VectorLength(color);
7480 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7483 if (flags & LP_RTWORLD)
7485 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7486 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7487 for (i = 0; i < numlights; i++)
7489 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7492 light = &dlight->rtlight;
7493 if (!(light->flags & flag))
7496 lightradius2 = light->radius * light->radius;
7497 VectorSubtract(light->shadoworigin, p, relativepoint);
7498 dist2 = VectorLength2(relativepoint);
7499 if (dist2 >= lightradius2)
7501 dist = sqrt(dist2) / light->radius;
7502 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
7503 if (intensity <= 0.0f)
7505 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)
7507 // scale down intensity to add to both ambient and diffuse
7508 //intensity *= 0.5f;
7509 VectorNormalize(relativepoint);
7510 VectorScale(light->currentcolor, intensity, color);
7511 VectorMA(sample , 0.5f , color, sample );
7512 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7513 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7514 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7515 // calculate a weighted average light direction as well
7516 intensity *= VectorLength(color);
7517 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7519 // FIXME: sample bouncegrid too!
7522 if (flags & LP_DYNLIGHT)
7525 for (i = 0;i < r_refdef.scene.numlights;i++)
7527 light = r_refdef.scene.lights[i];
7529 lightradius2 = light->radius * light->radius;
7530 VectorSubtract(light->shadoworigin, p, relativepoint);
7531 dist2 = VectorLength2(relativepoint);
7532 if (dist2 >= lightradius2)
7534 dist = sqrt(dist2) / light->radius;
7535 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
7536 if (intensity <= 0.0f)
7538 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)
7540 // scale down intensity to add to both ambient and diffuse
7541 //intensity *= 0.5f;
7542 VectorNormalize(relativepoint);
7543 VectorScale(light->currentcolor, intensity, color);
7544 VectorMA(sample , 0.5f , color, sample );
7545 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7546 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7547 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7548 // calculate a weighted average light direction as well
7549 intensity *= VectorLength(color);
7550 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7554 // calculate the direction we'll use to reduce the sample to a directional light source
7555 VectorCopy(sample + 12, dir);
7556 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
7557 VectorNormalize(dir);
7558 // extract the diffuse color along the chosen direction and scale it
7559 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
7560 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
7561 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
7562 // subtract some of diffuse from ambient
7563 VectorMA(sample, -0.333f, diffuse, ambient);
7564 // store the normalized lightdir
7565 VectorCopy(dir, lightdir);