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)
3193 int hitsupercontentsmask;
3194 int skipsupercontentsmask;
3199 //trace_t cliptrace2;
3200 //trace_t cliptrace3;
3201 unsigned int lightindex;
3202 unsigned int seed = (unsigned int)(realtime * 1000.0f);
3204 vec3_t baseshotcolor;
3213 // we'll need somewhere to store these
3214 r_shadow_bouncegrid_state.numsplatpaths = 0;
3215 r_shadow_bouncegrid_state.splatpaths = (r_shadow_bouncegrid_splatpath_t *)R_FrameData_Alloc(sizeof(r_shadow_bouncegrid_splatpath_t) * r_shadow_bouncegrid_state.maxsplatpaths);
3217 // figure out what we want to interact with
3218 if (settings.hitmodels)
3219 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;// | SUPERCONTENTS_LIQUIDSMASK;
3221 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
3222 skipsupercontentsmask = SUPERCONTENTS_SKY; // this allows the e1m5 sky shadow to work by ignoring the sky surfaces
3223 maxbounce = settings.maxbounce;
3225 for (lightindex = 0;lightindex < range2;lightindex++)
3227 if (lightindex < range)
3229 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3232 rtlight = &light->rtlight;
3235 rtlight = r_refdef.scene.lights[lightindex - range];
3236 // note that this code used to keep track of residual photons and
3237 // distribute them evenly to achieve exactly a desired photon count,
3238 // but that caused unwanted flickering in dynamic mode
3239 shootparticles = (int)floor(rtlight->photons * photonscaling);
3240 // skip if we won't be shooting any photons
3241 if (!shootparticles)
3243 radius = rtlight->radius * settings.lightradiusscale;
3244 s = settings.particleintensity / shootparticles;
3245 VectorScale(rtlight->photoncolor, s, baseshotcolor);
3246 r_refdef.stats[r_stat_bouncegrid_lights]++;
3247 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
3248 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
3250 if (settings.stablerandom > 0)
3251 seed = lightindex * 11937 + shotparticles;
3252 VectorCopy(baseshotcolor, shotcolor);
3253 VectorCopy(rtlight->shadoworigin, clipstart);
3254 if (settings.stablerandom < 0)
3255 VectorRandom(clipend);
3257 VectorCheeseRandom(clipend);
3258 VectorMA(clipstart, radius, clipend, clipend);
3259 for (bouncecount = 0;;bouncecount++)
3261 r_refdef.stats[r_stat_bouncegrid_traces]++;
3262 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
3263 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
3264 if (settings.staticmode)
3266 // static mode fires a LOT of rays but none of them are identical, so they are not cached
3267 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);
3271 // dynamic mode fires many rays and most will match the cache from the previous frame
3272 cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask, skipsupercontentsmask);
3274 if (bouncecount > 0 || settings.includedirectlighting)
3277 VectorCopy(cliptrace.endpos, hitpos);
3278 R_Shadow_BounceGrid_AddSplatPath(clipstart, hitpos, shotcolor);
3280 if (cliptrace.fraction >= 1.0f)
3282 r_refdef.stats[r_stat_bouncegrid_hits]++;
3283 if (bouncecount >= maxbounce)
3285 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
3286 // also clamp the resulting color to never add energy, even if the user requests extreme values
3287 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
3288 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
3290 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
3291 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
3292 surfcolor[0] = min(surfcolor[0], 1.0f);
3293 surfcolor[1] = min(surfcolor[1], 1.0f);
3294 surfcolor[2] = min(surfcolor[2], 1.0f);
3295 VectorMultiply(shotcolor, surfcolor, shotcolor);
3296 if (VectorLength2(baseshotcolor) == 0.0f)
3298 r_refdef.stats[r_stat_bouncegrid_bounces]++;
3299 if (settings.bounceanglediffuse)
3301 // random direction, primarily along plane normal
3302 s = VectorDistance(cliptrace.endpos, clipend);
3303 if (settings.stablerandom < 0)
3304 VectorRandom(clipend);
3306 VectorCheeseRandom(clipend);
3307 VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
3308 VectorNormalize(clipend);
3309 VectorScale(clipend, s, clipend);
3313 // reflect the remaining portion of the line across plane normal
3314 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
3315 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
3317 // calculate the new line start and end
3318 VectorCopy(cliptrace.endpos, clipstart);
3319 VectorAdd(clipstart, clipend, clipend);
3325 void R_Shadow_UpdateBounceGridTexture(void)
3327 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3328 r_shadow_bouncegrid_settings_t settings;
3329 qboolean enable = false;
3330 qboolean settingschanged;
3331 unsigned int range; // number of world lights
3332 unsigned int range1; // number of dynamic lights (or zero if disabled)
3333 unsigned int range2; // range+range1
3334 float photonscaling;
3336 enable = R_Shadow_BounceGrid_CheckEnable(flag);
3338 R_Shadow_BounceGrid_GenerateSettings(&settings);
3340 // changing intensity does not require an update
3341 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
3343 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
3345 // when settings change, we free everything as it is just simpler that way.
3346 if (settingschanged || !enable)
3348 // not enabled, make sure we free anything we don't need anymore.
3349 if (r_shadow_bouncegrid_state.texture)
3351 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3352 r_shadow_bouncegrid_state.texture = NULL;
3354 r_shadow_bouncegrid_state.numpixels = 0;
3355 r_shadow_bouncegrid_state.directional = false;
3361 // if all the settings seem identical to the previous update, return
3362 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
3365 // store the new settings
3366 r_shadow_bouncegrid_state.settings = settings;
3368 R_Shadow_BounceGrid_UpdateSpacing();
3370 // get the range of light numbers we'll be looping over:
3371 // range = static lights
3372 // range1 = dynamic lights (optional)
3373 // range2 = range + range1
3374 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3375 range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
3376 range2 = range + range1;
3378 // calculate weighting factors for distributing photons among the lights
3379 R_Shadow_BounceGrid_AssignPhotons(&settings, range, range1, range2, flag, &photonscaling);
3381 // trace the photons from lights and accumulate illumination
3382 R_Shadow_BounceGrid_TracePhotons(settings, range, range1, range2, photonscaling, flag);
3384 // clear the texture
3385 R_Shadow_BounceGrid_ClearPixels();
3387 // accumulate the light splatting into texture
3388 R_Shadow_BounceGrid_PerformSplats();
3390 // apply a mild blur filter to the texture
3391 R_Shadow_BounceGrid_BlurPixels();
3393 // convert the pixels to lower precision and upload the texture
3394 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
3397 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
3399 R_Shadow_RenderMode_Reset();
3400 GL_BlendFunc(GL_ONE, GL_ONE);
3401 GL_DepthRange(0, 1);
3402 GL_DepthTest(r_showshadowvolumes.integer < 2);
3403 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
3404 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
3405 GL_CullFace(GL_NONE);
3406 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
3409 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
3411 R_Shadow_RenderMode_Reset();
3412 GL_BlendFunc(GL_ONE, GL_ONE);
3413 GL_DepthRange(0, 1);
3414 GL_DepthTest(r_showlighting.integer < 2);
3415 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
3417 GL_DepthFunc(GL_EQUAL);
3418 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
3419 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
3422 void R_Shadow_RenderMode_End(void)
3424 R_Shadow_RenderMode_Reset();
3425 R_Shadow_RenderMode_ActiveLight(NULL);
3427 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3428 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3431 int bboxedges[12][2] =
3450 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
3452 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
3454 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
3455 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
3456 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
3457 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
3460 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
3461 return true; // invisible
3462 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
3463 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
3464 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
3465 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
3466 r_refdef.stats[r_stat_lights_scissored]++;
3470 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
3473 const float *vertex3f;
3474 const float *normal3f;
3476 float dist, dot, distintensity, shadeintensity, v[3], n[3];
3477 switch (r_shadow_rendermode)
3479 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3480 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3481 if (VectorLength2(diffusecolor) > 0)
3483 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)
3485 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3486 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3487 if ((dot = DotProduct(n, v)) < 0)
3489 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3490 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
3493 VectorCopy(ambientcolor, color4f);
3494 if (r_refdef.fogenabled)
3497 f = RSurf_FogVertex(vertex3f);
3498 VectorScale(color4f, f, color4f);
3505 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3507 VectorCopy(ambientcolor, color4f);
3508 if (r_refdef.fogenabled)
3511 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3512 f = RSurf_FogVertex(vertex3f);
3513 VectorScale(color4f + 4*i, f, color4f);
3519 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3520 if (VectorLength2(diffusecolor) > 0)
3522 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)
3524 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3525 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3527 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3528 if ((dot = DotProduct(n, v)) < 0)
3530 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3531 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3532 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3533 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3537 color4f[0] = ambientcolor[0] * distintensity;
3538 color4f[1] = ambientcolor[1] * distintensity;
3539 color4f[2] = ambientcolor[2] * distintensity;
3541 if (r_refdef.fogenabled)
3544 f = RSurf_FogVertex(vertex3f);
3545 VectorScale(color4f, f, color4f);
3549 VectorClear(color4f);
3555 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3557 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3558 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3560 color4f[0] = ambientcolor[0] * distintensity;
3561 color4f[1] = ambientcolor[1] * distintensity;
3562 color4f[2] = ambientcolor[2] * distintensity;
3563 if (r_refdef.fogenabled)
3566 f = RSurf_FogVertex(vertex3f);
3567 VectorScale(color4f, f, color4f);
3571 VectorClear(color4f);
3576 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3577 if (VectorLength2(diffusecolor) > 0)
3579 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)
3581 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3582 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3584 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3585 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3586 if ((dot = DotProduct(n, v)) < 0)
3588 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3589 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3590 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3591 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3595 color4f[0] = ambientcolor[0] * distintensity;
3596 color4f[1] = ambientcolor[1] * distintensity;
3597 color4f[2] = ambientcolor[2] * distintensity;
3599 if (r_refdef.fogenabled)
3602 f = RSurf_FogVertex(vertex3f);
3603 VectorScale(color4f, f, color4f);
3607 VectorClear(color4f);
3613 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3615 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3616 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3618 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3619 color4f[0] = ambientcolor[0] * distintensity;
3620 color4f[1] = ambientcolor[1] * distintensity;
3621 color4f[2] = ambientcolor[2] * distintensity;
3622 if (r_refdef.fogenabled)
3625 f = RSurf_FogVertex(vertex3f);
3626 VectorScale(color4f, f, color4f);
3630 VectorClear(color4f);
3640 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3642 // used to display how many times a surface is lit for level design purposes
3643 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3644 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3648 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
3650 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3651 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
3655 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3662 int newnumtriangles;
3666 int maxtriangles = 1024;
3667 int newelements[1024*3];
3668 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3669 for (renders = 0;renders < 4;renders++)
3674 newnumtriangles = 0;
3676 // due to low fillrate on the cards this vertex lighting path is
3677 // designed for, we manually cull all triangles that do not
3678 // contain a lit vertex
3679 // this builds batches of triangles from multiple surfaces and
3680 // renders them at once
3681 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3683 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3685 if (newnumtriangles)
3687 newfirstvertex = min(newfirstvertex, e[0]);
3688 newlastvertex = max(newlastvertex, e[0]);
3692 newfirstvertex = e[0];
3693 newlastvertex = e[0];
3695 newfirstvertex = min(newfirstvertex, e[1]);
3696 newlastvertex = max(newlastvertex, e[1]);
3697 newfirstvertex = min(newfirstvertex, e[2]);
3698 newlastvertex = max(newlastvertex, e[2]);
3704 if (newnumtriangles >= maxtriangles)
3706 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3707 newnumtriangles = 0;
3713 if (newnumtriangles >= 1)
3715 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3718 // if we couldn't find any lit triangles, exit early
3721 // now reduce the intensity for the next overbright pass
3722 // we have to clamp to 0 here incase the drivers have improper
3723 // handling of negative colors
3724 // (some old drivers even have improper handling of >1 color)
3726 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3728 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3730 c[0] = max(0, c[0] - 1);
3731 c[1] = max(0, c[1] - 1);
3732 c[2] = max(0, c[2] - 1);
3744 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
3746 // OpenGL 1.1 path (anything)
3747 float ambientcolorbase[3], diffusecolorbase[3];
3748 float ambientcolorpants[3], diffusecolorpants[3];
3749 float ambientcolorshirt[3], diffusecolorshirt[3];
3750 const float *surfacecolor = rsurface.texture->dlightcolor;
3751 const float *surfacepants = rsurface.colormap_pantscolor;
3752 const float *surfaceshirt = rsurface.colormap_shirtcolor;
3753 rtexture_t *basetexture = rsurface.texture->basetexture;
3754 rtexture_t *pantstexture = rsurface.texture->pantstexture;
3755 rtexture_t *shirttexture = rsurface.texture->shirttexture;
3756 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3757 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3758 ambientscale *= 2 * r_refdef.view.colorscale;
3759 diffusescale *= 2 * r_refdef.view.colorscale;
3760 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3761 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3762 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3763 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3764 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3765 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
3766 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3767 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
3768 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3769 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
3770 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
3771 R_Mesh_TexBind(0, basetexture);
3772 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
3773 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
3774 switch(r_shadow_rendermode)
3776 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3777 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
3778 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3779 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3780 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3782 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3783 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
3784 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
3785 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
3786 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3788 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3789 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
3790 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3791 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3792 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3794 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3799 //R_Mesh_TexBind(0, basetexture);
3800 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
3803 R_Mesh_TexBind(0, pantstexture);
3804 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
3808 R_Mesh_TexBind(0, shirttexture);
3809 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
3813 extern cvar_t gl_lightmaps;
3814 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3816 float ambientscale, diffusescale, specularscale;
3818 float lightcolor[3];
3819 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
3820 ambientscale = rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient;
3821 diffusescale = rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient);
3822 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3823 if (!r_shadow_usenormalmap.integer)
3825 ambientscale += 1.0f * diffusescale;
3829 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
3831 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
3834 VectorNegate(lightcolor, lightcolor);
3835 GL_BlendEquationSubtract(true);
3837 RSurf_SetupDepthAndCulling();
3838 switch (r_shadow_rendermode)
3840 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3841 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3842 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
3844 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3845 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
3847 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3848 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3849 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3850 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3851 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
3854 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3858 GL_BlendEquationSubtract(false);
3861 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)
3863 matrix4x4_t tempmatrix = *matrix;
3864 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3866 // if this light has been compiled before, free the associated data
3867 R_RTLight_Uncompile(rtlight);
3869 // clear it completely to avoid any lingering data
3870 memset(rtlight, 0, sizeof(*rtlight));
3872 // copy the properties
3873 rtlight->matrix_lighttoworld = tempmatrix;
3874 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3875 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3876 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3877 VectorCopy(color, rtlight->color);
3878 rtlight->cubemapname[0] = 0;
3879 if (cubemapname && cubemapname[0])
3880 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3881 rtlight->shadow = shadow;
3882 rtlight->corona = corona;
3883 rtlight->style = style;
3884 rtlight->isstatic = isstatic;
3885 rtlight->coronasizescale = coronasizescale;
3886 rtlight->ambientscale = ambientscale;
3887 rtlight->diffusescale = diffusescale;
3888 rtlight->specularscale = specularscale;
3889 rtlight->flags = flags;
3891 // compute derived data
3892 //rtlight->cullradius = rtlight->radius;
3893 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3894 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3895 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3896 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3897 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3898 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3899 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3902 // compiles rtlight geometry
3903 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3904 void R_RTLight_Compile(rtlight_t *rtlight)
3907 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3908 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3909 entity_render_t *ent = r_refdef.scene.worldentity;
3910 dp_model_t *model = r_refdef.scene.worldmodel;
3911 unsigned char *data;
3914 // compile the light
3915 rtlight->compiled = true;
3916 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3917 rtlight->static_numleafs = 0;
3918 rtlight->static_numleafpvsbytes = 0;
3919 rtlight->static_leaflist = NULL;
3920 rtlight->static_leafpvs = NULL;
3921 rtlight->static_numsurfaces = 0;
3922 rtlight->static_surfacelist = NULL;
3923 rtlight->static_shadowmap_receivers = 0x3F;
3924 rtlight->static_shadowmap_casters = 0x3F;
3925 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3926 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3927 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3928 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3929 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3930 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3932 if (model && model->GetLightInfo)
3934 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3935 r_shadow_compilingrtlight = rtlight;
3936 R_FrameData_SetMark();
3937 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);
3938 R_FrameData_ReturnToMark();
3939 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3940 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3941 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3942 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3943 rtlight->static_numsurfaces = numsurfaces;
3944 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3945 rtlight->static_numleafs = numleafs;
3946 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3947 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3948 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3949 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3950 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3951 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3952 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3953 if (rtlight->static_numsurfaces)
3954 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3955 if (rtlight->static_numleafs)
3956 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3957 if (rtlight->static_numleafpvsbytes)
3958 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3959 if (rtlight->static_numshadowtrispvsbytes)
3960 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3961 if (rtlight->static_numlighttrispvsbytes)
3962 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3963 R_FrameData_SetMark();
3964 switch (rtlight->shadowmode)
3966 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3967 if (model->CompileShadowMap && rtlight->shadow)
3968 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3971 if (model->CompileShadowVolume && rtlight->shadow)
3972 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3975 R_FrameData_ReturnToMark();
3976 // now we're done compiling the rtlight
3977 r_shadow_compilingrtlight = NULL;
3981 // use smallest available cullradius - box radius or light radius
3982 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3983 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3985 shadowzpasstris = 0;
3986 if (rtlight->static_meshchain_shadow_zpass)
3987 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3988 shadowzpasstris += mesh->numtriangles;
3990 shadowzfailtris = 0;
3991 if (rtlight->static_meshchain_shadow_zfail)
3992 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3993 shadowzfailtris += mesh->numtriangles;
3996 if (rtlight->static_numlighttrispvsbytes)
3997 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3998 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
4002 if (rtlight->static_numshadowtrispvsbytes)
4003 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
4004 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
4007 if (developer_extra.integer)
4008 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);
4011 void R_RTLight_Uncompile(rtlight_t *rtlight)
4013 if (rtlight->compiled)
4015 if (rtlight->static_meshchain_shadow_zpass)
4016 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
4017 rtlight->static_meshchain_shadow_zpass = NULL;
4018 if (rtlight->static_meshchain_shadow_zfail)
4019 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
4020 rtlight->static_meshchain_shadow_zfail = NULL;
4021 if (rtlight->static_meshchain_shadow_shadowmap)
4022 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
4023 rtlight->static_meshchain_shadow_shadowmap = NULL;
4024 // these allocations are grouped
4025 if (rtlight->static_surfacelist)
4026 Mem_Free(rtlight->static_surfacelist);
4027 rtlight->static_numleafs = 0;
4028 rtlight->static_numleafpvsbytes = 0;
4029 rtlight->static_leaflist = NULL;
4030 rtlight->static_leafpvs = NULL;
4031 rtlight->static_numsurfaces = 0;
4032 rtlight->static_surfacelist = NULL;
4033 rtlight->static_numshadowtrispvsbytes = 0;
4034 rtlight->static_shadowtrispvs = NULL;
4035 rtlight->static_numlighttrispvsbytes = 0;
4036 rtlight->static_lighttrispvs = NULL;
4037 rtlight->compiled = false;
4041 void R_Shadow_UncompileWorldLights(void)
4045 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4046 for (lightindex = 0;lightindex < range;lightindex++)
4048 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4051 R_RTLight_Uncompile(&light->rtlight);
4055 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
4059 // reset the count of frustum planes
4060 // see rtlight->cached_frustumplanes definition for how much this array
4062 rtlight->cached_numfrustumplanes = 0;
4064 if (r_trippy.integer)
4067 // haven't implemented a culling path for ortho rendering
4068 if (!r_refdef.view.useperspective)
4070 // check if the light is on screen and copy the 4 planes if it is
4071 for (i = 0;i < 4;i++)
4072 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4075 for (i = 0;i < 4;i++)
4076 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4081 // generate a deformed frustum that includes the light origin, this is
4082 // used to cull shadow casting surfaces that can not possibly cast a
4083 // shadow onto the visible light-receiving surfaces, which can be a
4086 // if the light origin is onscreen the result will be 4 planes exactly
4087 // if the light origin is offscreen on only one axis the result will
4088 // be exactly 5 planes (split-side case)
4089 // if the light origin is offscreen on two axes the result will be
4090 // exactly 4 planes (stretched corner case)
4091 for (i = 0;i < 4;i++)
4093 // quickly reject standard frustum planes that put the light
4094 // origin outside the frustum
4095 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4098 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4100 // if all the standard frustum planes were accepted, the light is onscreen
4101 // otherwise we need to generate some more planes below...
4102 if (rtlight->cached_numfrustumplanes < 4)
4104 // at least one of the stock frustum planes failed, so we need to
4105 // create one or two custom planes to enclose the light origin
4106 for (i = 0;i < 4;i++)
4108 // create a plane using the view origin and light origin, and a
4109 // single point from the frustum corner set
4110 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
4111 VectorNormalize(plane.normal);
4112 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
4113 // see if this plane is backwards and flip it if so
4114 for (j = 0;j < 4;j++)
4115 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4119 VectorNegate(plane.normal, plane.normal);
4121 // flipped plane, test again to see if it is now valid
4122 for (j = 0;j < 4;j++)
4123 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4125 // if the plane is still not valid, then it is dividing the
4126 // frustum and has to be rejected
4130 // we have created a valid plane, compute extra info
4131 PlaneClassify(&plane);
4133 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4135 // if we've found 5 frustum planes then we have constructed a
4136 // proper split-side case and do not need to keep searching for
4137 // planes to enclose the light origin
4138 if (rtlight->cached_numfrustumplanes == 5)
4146 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
4148 plane = rtlight->cached_frustumplanes[i];
4149 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));
4154 // now add the light-space box planes if the light box is rotated, as any
4155 // caster outside the oriented light box is irrelevant (even if it passed
4156 // the worldspace light box, which is axial)
4157 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
4159 for (i = 0;i < 6;i++)
4163 v[i >> 1] = (i & 1) ? -1 : 1;
4164 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
4165 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
4166 plane.dist = VectorNormalizeLength(plane.normal);
4167 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
4168 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4174 // add the world-space reduced box planes
4175 for (i = 0;i < 6;i++)
4177 VectorClear(plane.normal);
4178 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
4179 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
4180 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4189 // reduce all plane distances to tightly fit the rtlight cull box, which
4191 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4192 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4193 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4194 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4195 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4196 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4197 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4198 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4199 oldnum = rtlight->cached_numfrustumplanes;
4200 rtlight->cached_numfrustumplanes = 0;
4201 for (j = 0;j < oldnum;j++)
4203 // find the nearest point on the box to this plane
4204 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
4205 for (i = 1;i < 8;i++)
4207 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
4208 if (bestdist > dist)
4211 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);
4212 // if the nearest point is near or behind the plane, we want this
4213 // plane, otherwise the plane is useless as it won't cull anything
4214 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
4216 PlaneClassify(&rtlight->cached_frustumplanes[j]);
4217 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
4224 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
4228 RSurf_ActiveWorldEntity();
4230 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4233 GL_CullFace(GL_NONE);
4234 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
4235 for (;mesh;mesh = mesh->next)
4237 if (!mesh->sidetotals[r_shadow_shadowmapside])
4239 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
4240 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4241 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);
4245 else if (r_refdef.scene.worldentity->model)
4246 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);
4248 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4251 static void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
4253 qboolean zpass = false;
4256 int surfacelistindex;
4257 msurface_t *surface;
4259 // if triangle neighbors are disabled, shadowvolumes are disabled
4260 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
4263 RSurf_ActiveWorldEntity();
4265 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4268 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
4270 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
4271 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
4273 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
4274 for (;mesh;mesh = mesh->next)
4276 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->numtriangles;
4277 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4278 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
4280 // increment stencil if frontface is infront of depthbuffer
4281 GL_CullFace(r_refdef.view.cullface_back);
4282 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
4283 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);
4284 // decrement stencil if backface is infront of depthbuffer
4285 GL_CullFace(r_refdef.view.cullface_front);
4286 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
4288 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
4290 // decrement stencil if backface is behind depthbuffer
4291 GL_CullFace(r_refdef.view.cullface_front);
4292 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
4293 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);
4294 // increment stencil if frontface is behind depthbuffer
4295 GL_CullFace(r_refdef.view.cullface_back);
4296 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
4298 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);
4302 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
4304 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
4305 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
4306 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
4308 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
4309 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
4310 if (CHECKPVSBIT(trispvs, t))
4311 shadowmarklist[numshadowmark++] = t;
4313 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);
4315 else if (numsurfaces)
4317 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);
4320 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4323 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
4325 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
4326 vec_t relativeshadowradius;
4327 RSurf_ActiveModelEntity(ent, false, false, false);
4328 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
4329 // we need to re-init the shader for each entity because the matrix changed
4330 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
4331 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
4332 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
4333 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
4334 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
4335 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
4336 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
4337 switch (r_shadow_rendermode)
4339 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
4340 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4343 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4346 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4349 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
4351 // set up properties for rendering light onto this entity
4352 RSurf_ActiveModelEntity(ent, true, true, false);
4353 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
4354 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4355 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4356 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4359 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
4361 if (!r_refdef.scene.worldmodel->DrawLight)
4364 // set up properties for rendering light onto this entity
4365 RSurf_ActiveWorldEntity();
4366 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
4367 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4368 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4369 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4371 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
4373 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4376 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
4378 dp_model_t *model = ent->model;
4379 if (!model->DrawLight)
4382 R_Shadow_SetupEntityLight(ent);
4384 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
4386 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4389 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
4393 int numleafs, numsurfaces;
4394 int *leaflist, *surfacelist;
4395 unsigned char *leafpvs;
4396 unsigned char *shadowtrispvs;
4397 unsigned char *lighttrispvs;
4398 //unsigned char *surfacesides;
4399 int numlightentities;
4400 int numlightentities_noselfshadow;
4401 int numshadowentities;
4402 int numshadowentities_noselfshadow;
4403 // FIXME: bounds check lightentities and shadowentities, etc.
4404 static entity_render_t *lightentities[MAX_EDICTS];
4405 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
4406 static entity_render_t *shadowentities[MAX_EDICTS];
4407 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
4409 qboolean castshadows;
4411 rtlight->draw = false;
4412 rtlight->cached_numlightentities = 0;
4413 rtlight->cached_numlightentities_noselfshadow = 0;
4414 rtlight->cached_numshadowentities = 0;
4415 rtlight->cached_numshadowentities_noselfshadow = 0;
4416 rtlight->cached_numsurfaces = 0;
4417 rtlight->cached_lightentities = NULL;
4418 rtlight->cached_lightentities_noselfshadow = NULL;
4419 rtlight->cached_shadowentities = NULL;
4420 rtlight->cached_shadowentities_noselfshadow = NULL;
4421 rtlight->cached_shadowtrispvs = NULL;
4422 rtlight->cached_lighttrispvs = NULL;
4423 rtlight->cached_surfacelist = NULL;
4424 rtlight->shadowmapsidesize = 0;
4426 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
4427 // skip lights that are basically invisible (color 0 0 0)
4428 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
4430 // loading is done before visibility checks because loading should happen
4431 // all at once at the start of a level, not when it stalls gameplay.
4432 // (especially important to benchmarks)
4434 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
4436 if (rtlight->compiled)
4437 R_RTLight_Uncompile(rtlight);
4438 R_RTLight_Compile(rtlight);
4442 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
4444 // look up the light style value at this time
4445 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4446 VectorScale(rtlight->color, f, rtlight->currentcolor);
4448 if (rtlight->selected)
4450 f = 2 + sin(realtime * M_PI * 4.0);
4451 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
4455 // if lightstyle is currently off, don't draw the light
4456 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
4459 // skip processing on corona-only lights
4463 // if the light box is offscreen, skip it
4464 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
4467 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
4468 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
4470 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4472 // 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
4473 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
4476 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
4478 // compiled light, world available and can receive realtime lighting
4479 // retrieve leaf information
4480 numleafs = rtlight->static_numleafs;
4481 leaflist = rtlight->static_leaflist;
4482 leafpvs = rtlight->static_leafpvs;
4483 numsurfaces = rtlight->static_numsurfaces;
4484 surfacelist = rtlight->static_surfacelist;
4485 //surfacesides = NULL;
4486 shadowtrispvs = rtlight->static_shadowtrispvs;
4487 lighttrispvs = rtlight->static_lighttrispvs;
4489 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4491 // dynamic light, world available and can receive realtime lighting
4492 // calculate lit surfaces and leafs
4493 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);
4494 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4495 leaflist = r_shadow_buffer_leaflist;
4496 leafpvs = r_shadow_buffer_leafpvs;
4497 surfacelist = r_shadow_buffer_surfacelist;
4498 //surfacesides = r_shadow_buffer_surfacesides;
4499 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4500 lighttrispvs = r_shadow_buffer_lighttrispvs;
4501 // if the reduced leaf bounds are offscreen, skip it
4502 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4513 //surfacesides = NULL;
4514 shadowtrispvs = NULL;
4515 lighttrispvs = NULL;
4517 // check if light is illuminating any visible leafs
4520 for (i = 0; i < numleafs; i++)
4521 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4527 // make a list of lit entities and shadow casting entities
4528 numlightentities = 0;
4529 numlightentities_noselfshadow = 0;
4530 numshadowentities = 0;
4531 numshadowentities_noselfshadow = 0;
4533 // add dynamic entities that are lit by the light
4534 for (i = 0; i < r_refdef.scene.numentities; i++)
4537 entity_render_t *ent = r_refdef.scene.entities[i];
4539 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4541 // skip the object entirely if it is not within the valid
4542 // shadow-casting region (which includes the lit region)
4543 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
4545 if (!(model = ent->model))
4547 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4549 // this entity wants to receive light, is visible, and is
4550 // inside the light box
4551 // TODO: check if the surfaces in the model can receive light
4552 // so now check if it's in a leaf seen by the light
4553 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))
4555 if (ent->flags & RENDER_NOSELFSHADOW)
4556 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
4558 lightentities[numlightentities++] = ent;
4559 // since it is lit, it probably also casts a shadow...
4560 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4561 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4562 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4564 // note: exterior models without the RENDER_NOSELFSHADOW
4565 // flag still create a RENDER_NOSELFSHADOW shadow but
4566 // are lit normally, this means that they are
4567 // self-shadowing but do not shadow other
4568 // RENDER_NOSELFSHADOW entities such as the gun
4569 // (very weird, but keeps the player shadow off the gun)
4570 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4571 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4573 shadowentities[numshadowentities++] = ent;
4576 else if (ent->flags & RENDER_SHADOW)
4578 // this entity is not receiving light, but may still need to
4580 // TODO: check if the surfaces in the model can cast shadow
4581 // now check if it is in a leaf seen by the light
4582 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))
4584 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4585 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4586 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4588 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4589 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4591 shadowentities[numshadowentities++] = ent;
4596 // return if there's nothing at all to light
4597 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4600 // count this light in the r_speeds
4601 r_refdef.stats[r_stat_lights]++;
4603 // flag it as worth drawing later
4604 rtlight->draw = true;
4606 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
4607 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4609 numshadowentities = numshadowentities_noselfshadow = 0;
4610 rtlight->castshadows = castshadows;
4612 // cache all the animated entities that cast a shadow but are not visible
4613 for (i = 0; i < numshadowentities; i++)
4614 R_AnimCache_GetEntity(shadowentities[i], false, false);
4615 for (i = 0; i < numshadowentities_noselfshadow; i++)
4616 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4618 // 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)
4619 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
4621 for (i = 0; i < numshadowentities_noselfshadow; i++)
4622 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
4623 numshadowentities_noselfshadow = 0;
4626 // we can convert noselfshadow to regular if there are no casters of that type
4627 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
4629 for (i = 0; i < numlightentities_noselfshadow; i++)
4630 lightentities[numlightentities++] = lightentities_noselfshadow[i];
4631 numlightentities_noselfshadow = 0;
4634 // allocate some temporary memory for rendering this light later in the frame
4635 // reusable buffers need to be copied, static data can be used as-is
4636 rtlight->cached_numlightentities = numlightentities;
4637 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
4638 rtlight->cached_numshadowentities = numshadowentities;
4639 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4640 rtlight->cached_numsurfaces = numsurfaces;
4641 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4642 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4643 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4644 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4645 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4647 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4648 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4649 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4650 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4651 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4655 // compiled light data
4656 rtlight->cached_shadowtrispvs = shadowtrispvs;
4657 rtlight->cached_lighttrispvs = lighttrispvs;
4658 rtlight->cached_surfacelist = surfacelist;
4661 if (R_Shadow_ShadowMappingEnabled())
4663 // figure out the shadowmapping parameters for this light
4664 vec3_t nearestpoint;
4667 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4668 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4669 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4670 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4671 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
4672 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4673 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4674 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4675 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
4679 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
4683 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4684 int numlightentities;
4685 int numlightentities_noselfshadow;
4686 int numshadowentities;
4687 int numshadowentities_noselfshadow;
4688 entity_render_t **lightentities;
4689 entity_render_t **lightentities_noselfshadow;
4690 entity_render_t **shadowentities;
4691 entity_render_t **shadowentities_noselfshadow;
4693 static unsigned char entitysides[MAX_EDICTS];
4694 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4700 matrix4x4_t radiustolight;
4702 // check if we cached this light this frame (meaning it is worth drawing)
4703 if (!rtlight->draw || !rtlight->castshadows)
4706 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
4707 if (rtlight->shadowmapatlassidesize == 0)
4709 rtlight->castshadows = false;
4713 // set up a scissor rectangle for this light
4714 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4717 // don't let sound skip if going slow
4718 if (r_refdef.scene.extraupdate)
4721 numlightentities = rtlight->cached_numlightentities;
4722 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4723 numshadowentities = rtlight->cached_numshadowentities;
4724 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4725 numsurfaces = rtlight->cached_numsurfaces;
4726 lightentities = rtlight->cached_lightentities;
4727 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4728 shadowentities = rtlight->cached_shadowentities;
4729 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4730 shadowtrispvs = rtlight->cached_shadowtrispvs;
4731 lighttrispvs = rtlight->cached_lighttrispvs;
4732 surfacelist = rtlight->cached_surfacelist;
4734 // make this the active rtlight for rendering purposes
4735 R_Shadow_RenderMode_ActiveLight(rtlight);
4737 radiustolight = rtlight->matrix_worldtolight;
4738 Matrix4x4_Abs(&radiustolight);
4740 size = rtlight->shadowmapatlassidesize;
4741 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4743 surfacesides = NULL;
4748 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4750 castermask = rtlight->static_shadowmap_casters;
4751 receivermask = rtlight->static_shadowmap_receivers;
4755 surfacesides = r_shadow_buffer_surfacesides;
4756 for (i = 0; i < numsurfaces; i++)
4758 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4759 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4760 castermask |= surfacesides[i];
4761 receivermask |= surfacesides[i];
4766 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
4767 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4768 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
4769 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4771 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4775 for (i = 0; i < numshadowentities; i++)
4776 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4777 for (i = 0; i < numshadowentities_noselfshadow; i++)
4778 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4781 // there is no need to render shadows for sides that have no receivers...
4782 castermask &= receivermask;
4784 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
4786 // render shadow casters into shadowmaps for this light
4787 for (side = 0; side < 6; side++)
4789 int bit = 1 << side;
4790 if (castermask & bit)
4792 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
4794 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4795 for (i = 0; i < numshadowentities; i++)
4796 if (entitysides[i] & bit)
4797 R_Shadow_DrawEntityShadow(shadowentities[i]);
4798 for (i = 0; i < numshadowentities_noselfshadow; i++)
4799 if (entitysides_noselfshadow[i] & bit)
4800 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4803 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
4804 if (numshadowentities_noselfshadow)
4806 for (side = 0; side < 6; side++)
4808 int bit = 1 << side;
4809 if (castermask & bit)
4811 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
4813 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4814 for (i = 0; i < numshadowentities; i++)
4815 if (entitysides[i] & bit)
4816 R_Shadow_DrawEntityShadow(shadowentities[i]);
4822 static void R_Shadow_DrawLight(rtlight_t *rtlight)
4826 unsigned char *shadowtrispvs, *lighttrispvs;
4827 int numlightentities;
4828 int numlightentities_noselfshadow;
4829 int numshadowentities;
4830 int numshadowentities_noselfshadow;
4831 entity_render_t **lightentities;
4832 entity_render_t **lightentities_noselfshadow;
4833 entity_render_t **shadowentities;
4834 entity_render_t **shadowentities_noselfshadow;
4836 qboolean castshadows;
4838 // check if we cached this light this frame (meaning it is worth drawing)
4842 // set up a scissor rectangle for this light
4843 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4846 // don't let sound skip if going slow
4847 if (r_refdef.scene.extraupdate)
4850 numlightentities = rtlight->cached_numlightentities;
4851 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4852 numshadowentities = rtlight->cached_numshadowentities;
4853 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4854 numsurfaces = rtlight->cached_numsurfaces;
4855 lightentities = rtlight->cached_lightentities;
4856 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4857 shadowentities = rtlight->cached_shadowentities;
4858 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4859 shadowtrispvs = rtlight->cached_shadowtrispvs;
4860 lighttrispvs = rtlight->cached_lighttrispvs;
4861 surfacelist = rtlight->cached_surfacelist;
4862 castshadows = rtlight->castshadows;
4864 // make this the active rtlight for rendering purposes
4865 R_Shadow_RenderMode_ActiveLight(rtlight);
4867 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4869 // optionally draw visible shape of the shadow volumes
4870 // for performance analysis by level designers
4871 R_Shadow_RenderMode_VisibleShadowVolumes();
4873 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4874 for (i = 0;i < numshadowentities;i++)
4875 R_Shadow_DrawEntityShadow(shadowentities[i]);
4876 for (i = 0;i < numshadowentities_noselfshadow;i++)
4877 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4878 R_Shadow_RenderMode_VisibleLighting(false, false);
4881 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4883 // optionally draw the illuminated areas
4884 // for performance analysis by level designers
4885 R_Shadow_RenderMode_VisibleLighting(false, false);
4887 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4888 for (i = 0;i < numlightentities;i++)
4889 R_Shadow_DrawEntityLight(lightentities[i]);
4890 for (i = 0;i < numlightentities_noselfshadow;i++)
4891 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4894 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4898 float shadowmapoffsetnoselfshadow = 0;
4899 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4900 Matrix4x4_Abs(&radiustolight);
4902 size = rtlight->shadowmapatlassidesize;
4903 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4905 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
4907 if (rtlight->cached_numshadowentities_noselfshadow)
4908 shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
4910 // render lighting using the depth texture as shadowmap
4911 // draw lighting in the unmasked areas
4912 if (numsurfaces + numlightentities)
4914 R_Shadow_RenderMode_Lighting(false, false, true, false);
4915 // draw lighting in the unmasked areas
4917 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4918 for (i = 0; i < numlightentities; i++)
4919 R_Shadow_DrawEntityLight(lightentities[i]);
4921 // offset to the noselfshadow part of the atlas and draw those too
4922 if (numlightentities_noselfshadow)
4924 R_Shadow_RenderMode_Lighting(false, false, true, true);
4925 for (i = 0; i < numlightentities_noselfshadow; i++)
4926 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4929 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
4930 if (r_shadow_usingdeferredprepass)
4931 R_Shadow_RenderMode_DrawDeferredLight(true);
4933 else if (castshadows && vid.stencil)
4935 // draw stencil shadow volumes to mask off pixels that are in shadow
4936 // so that they won't receive lighting
4937 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4938 R_Shadow_ClearStencil();
4941 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4942 for (i = 0;i < numshadowentities;i++)
4943 R_Shadow_DrawEntityShadow(shadowentities[i]);
4945 // draw lighting in the unmasked areas
4946 R_Shadow_RenderMode_Lighting(true, false, false, false);
4947 for (i = 0;i < numlightentities_noselfshadow;i++)
4948 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4950 for (i = 0;i < numshadowentities_noselfshadow;i++)
4951 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4953 // draw lighting in the unmasked areas
4954 R_Shadow_RenderMode_Lighting(true, false, false, false);
4956 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4957 for (i = 0;i < numlightentities;i++)
4958 R_Shadow_DrawEntityLight(lightentities[i]);
4960 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
4961 if (r_shadow_usingdeferredprepass)
4962 R_Shadow_RenderMode_DrawDeferredLight(false);
4966 // draw lighting in the unmasked areas
4967 R_Shadow_RenderMode_Lighting(false, false, false, false);
4969 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4970 for (i = 0;i < numlightentities;i++)
4971 R_Shadow_DrawEntityLight(lightentities[i]);
4972 for (i = 0;i < numlightentities_noselfshadow;i++)
4973 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4975 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
4976 if (r_shadow_usingdeferredprepass)
4977 R_Shadow_RenderMode_DrawDeferredLight(false);
4981 static void R_Shadow_FreeDeferred(void)
4983 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
4984 r_shadow_prepassgeometryfbo = 0;
4986 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
4987 r_shadow_prepasslightingdiffusespecularfbo = 0;
4989 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
4990 r_shadow_prepasslightingdiffusefbo = 0;
4992 if (r_shadow_prepassgeometrydepthbuffer)
4993 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
4994 r_shadow_prepassgeometrydepthbuffer = NULL;
4996 if (r_shadow_prepassgeometrynormalmaptexture)
4997 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4998 r_shadow_prepassgeometrynormalmaptexture = NULL;
5000 if (r_shadow_prepasslightingdiffusetexture)
5001 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
5002 r_shadow_prepasslightingdiffusetexture = NULL;
5004 if (r_shadow_prepasslightingspeculartexture)
5005 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
5006 r_shadow_prepasslightingspeculartexture = NULL;
5009 void R_Shadow_DrawPrepass(void)
5013 entity_render_t *ent;
5014 float clearcolor[4];
5016 R_Mesh_ResetTextureState();
5018 GL_ColorMask(1,1,1,1);
5019 GL_BlendFunc(GL_ONE, GL_ZERO);
5022 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5023 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
5024 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
5025 if (r_timereport_active)
5026 R_TimeReport("prepasscleargeom");
5028 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
5029 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
5030 if (r_timereport_active)
5031 R_TimeReport("prepassworld");
5033 for (i = 0;i < r_refdef.scene.numentities;i++)
5035 if (!r_refdef.viewcache.entityvisible[i])
5037 ent = r_refdef.scene.entities[i];
5038 if (ent->model && ent->model->DrawPrepass != NULL)
5039 ent->model->DrawPrepass(ent);
5042 if (r_timereport_active)
5043 R_TimeReport("prepassmodels");
5045 GL_DepthMask(false);
5046 GL_ColorMask(1,1,1,1);
5049 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5050 Vector4Set(clearcolor, 0, 0, 0, 0);
5051 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
5052 if (r_timereport_active)
5053 R_TimeReport("prepassclearlit");
5055 R_Shadow_RenderMode_Begin();
5057 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5058 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5060 R_Shadow_RenderMode_End();
5062 if (r_timereport_active)
5063 R_TimeReport("prepasslights");
5066 #define MAX_SCENELIGHTS 65536
5067 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
5069 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
5071 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
5073 r_shadow_scenemaxlights *= 2;
5074 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
5075 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
5077 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
5081 void R_Shadow_DrawLightSprites(void);
5082 void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
5091 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
5092 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
5093 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
5095 if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
5096 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
5097 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
5098 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
5099 r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) ||
5100 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
5101 r_shadow_shadowmapborder != shadowmapborder ||
5102 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
5103 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
5104 R_Shadow_FreeShadowMaps();
5106 r_shadow_fb_fbo = fbo;
5107 r_shadow_fb_depthtexture = depthtexture;
5108 r_shadow_fb_colortexture = colortexture;
5110 r_shadow_usingshadowmaportho = false;
5112 switch (vid.renderpath)
5114 case RENDERPATH_GL20:
5115 case RENDERPATH_D3D9:
5116 case RENDERPATH_D3D10:
5117 case RENDERPATH_D3D11:
5118 case RENDERPATH_SOFT:
5120 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
5122 r_shadow_usingdeferredprepass = false;
5123 if (r_shadow_prepass_width)
5124 R_Shadow_FreeDeferred();
5125 r_shadow_prepass_width = r_shadow_prepass_height = 0;
5129 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
5131 R_Shadow_FreeDeferred();
5133 r_shadow_usingdeferredprepass = true;
5134 r_shadow_prepass_width = vid.width;
5135 r_shadow_prepass_height = vid.height;
5136 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
5137 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);
5138 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);
5139 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);
5141 // set up the geometry pass fbo (depth + normalmap)
5142 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5143 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5144 // render depth into a renderbuffer and other important properties into the normalmap texture
5146 // set up the lighting pass fbo (diffuse + specular)
5147 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5148 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5149 // render diffuse into one texture and specular into another,
5150 // with depth and normalmap bound as textures,
5151 // with depth bound as attachment as well
5153 // set up the lighting pass fbo (diffuse)
5154 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5155 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5156 // render diffuse into one texture,
5157 // with depth and normalmap bound as textures,
5158 // with depth bound as attachment as well
5162 case RENDERPATH_GL11:
5163 case RENDERPATH_GL13:
5164 case RENDERPATH_GLES1:
5165 case RENDERPATH_GLES2:
5166 r_shadow_usingdeferredprepass = false;
5170 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);
5172 r_shadow_scenenumlights = 0;
5173 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5174 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5175 for (lightindex = 0; lightindex < range; lightindex++)
5177 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5178 if (light && (light->flags & flag))
5180 R_Shadow_PrepareLight(&light->rtlight);
5181 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5184 if (r_refdef.scene.rtdlight)
5186 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5188 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
5189 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
5192 else if (gl_flashblend.integer)
5194 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5196 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
5197 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
5198 VectorScale(rtlight->color, f, rtlight->currentcolor);
5202 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
5203 if (r_shadow_debuglight.integer >= 0)
5205 r_shadow_scenenumlights = 0;
5206 lightindex = r_shadow_debuglight.integer;
5207 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5210 R_Shadow_PrepareLight(&light->rtlight);
5211 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5215 // if we're doing shadowmaps we need to prepare the atlas layout now
5216 if (R_Shadow_ShadowMappingEnabled())
5220 // allocate shadowmaps in the atlas now
5221 // 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...
5222 for (lod = 0; lod < 16; lod++)
5224 int packing_success = 0;
5225 int packing_failure = 0;
5226 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
5227 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
5228 if (r_shadow_shadowmapatlas_modelshadows_size)
5229 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);
5230 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5232 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
5233 int size = rtlight->shadowmapsidesize >> lod;
5235 if (!rtlight->castshadows)
5237 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
5240 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
5241 if (rtlight->cached_numshadowentities_noselfshadow)
5243 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
5245 rtlight->shadowmapatlassidesize = size;
5250 // note down that we failed to pack this one, it will have to disable shadows
5251 rtlight->shadowmapatlassidesize = 0;
5255 // generally everything fits and we stop here on the first iteration
5256 if (packing_failure == 0)
5261 if (r_editlights.integer)
5262 R_Shadow_DrawLightSprites();
5265 void R_Shadow_DrawShadowMaps(void)
5267 R_Shadow_RenderMode_Begin();
5268 R_Shadow_RenderMode_ActiveLight(NULL);
5270 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
5271 R_Shadow_ClearShadowMapTexture();
5273 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
5274 if (r_shadow_shadowmapatlas_modelshadows_size)
5276 R_Shadow_DrawModelShadowMaps();
5277 // don't let sound skip if going slow
5278 if (r_refdef.scene.extraupdate)
5282 if (R_Shadow_ShadowMappingEnabled())
5285 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5286 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
5289 R_Shadow_RenderMode_End();
5292 void R_Shadow_DrawLights(void)
5296 R_Shadow_RenderMode_Begin();
5298 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5299 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5301 R_Shadow_RenderMode_End();
5304 #define MAX_MODELSHADOWS 1024
5305 static int r_shadow_nummodelshadows;
5306 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
5308 void R_Shadow_PrepareModelShadows(void)
5311 float scale, size, radius, dot1, dot2;
5312 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5313 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
5314 entity_render_t *ent;
5316 r_shadow_nummodelshadows = 0;
5317 r_shadow_shadowmapatlas_modelshadows_size = 0;
5319 if (!r_refdef.scene.numentities || r_refdef.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
5322 switch (r_shadow_shadowmode)
5324 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
5325 if (r_shadows.integer >= 2)
5328 case R_SHADOW_SHADOWMODE_STENCIL:
5331 for (i = 0; i < r_refdef.scene.numentities; i++)
5333 ent = r_refdef.scene.entities[i];
5334 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5336 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5338 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5339 R_AnimCache_GetEntity(ent, false, false);
5347 size = 2 * r_shadow_shadowmapmaxsize;
5348 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
5349 radius = 0.5f * size / scale;
5351 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5352 VectorCopy(prvmshadowdir, shadowdir);
5353 VectorNormalize(shadowdir);
5354 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5355 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5356 if (fabs(dot1) <= fabs(dot2))
5357 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5359 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5360 VectorNormalize(shadowforward);
5361 CrossProduct(shadowdir, shadowforward, shadowright);
5362 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5363 VectorCopy(prvmshadowfocus, shadowfocus);
5364 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5365 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5366 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5367 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5368 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5370 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5372 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5373 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5374 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5375 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5376 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5377 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5379 for (i = 0; i < r_refdef.scene.numentities; i++)
5381 ent = r_refdef.scene.entities[i];
5382 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
5384 // cast shadows from anything of the map (submodels are optional)
5385 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5387 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5389 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5390 R_AnimCache_GetEntity(ent, false, false);
5394 if (r_shadow_nummodelshadows)
5396 r_shadow_shadowmapatlas_modelshadows_x = 0;
5397 r_shadow_shadowmapatlas_modelshadows_y = 0;
5398 r_shadow_shadowmapatlas_modelshadows_size = size;
5402 static void R_Shadow_DrawModelShadowMaps(void)
5405 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
5406 entity_render_t *ent;
5407 vec3_t relativelightorigin;
5408 vec3_t relativelightdirection, relativeforward, relativeright;
5409 vec3_t relativeshadowmins, relativeshadowmaxs;
5410 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
5411 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5413 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
5414 r_viewport_t viewport;
5416 size = r_shadow_shadowmapatlas_modelshadows_size;
5417 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
5418 radius = 0.5f / scale;
5419 nearclip = -r_shadows_throwdistance.value;
5420 farclip = r_shadows_throwdistance.value;
5421 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);
5423 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
5424 r_shadow_modelshadowmap_parameters[0] = size;
5425 r_shadow_modelshadowmap_parameters[1] = size;
5426 r_shadow_modelshadowmap_parameters[2] = 1.0;
5427 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
5428 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
5429 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
5430 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
5431 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
5432 r_shadow_usingshadowmaportho = true;
5434 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5435 VectorCopy(prvmshadowdir, shadowdir);
5436 VectorNormalize(shadowdir);
5437 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5438 VectorCopy(prvmshadowfocus, shadowfocus);
5439 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5440 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5441 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5442 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5443 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5444 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5445 if (fabs(dot1) <= fabs(dot2))
5446 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5448 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5449 VectorNormalize(shadowforward);
5450 VectorM(scale, shadowforward, &m[0]);
5451 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5453 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
5454 CrossProduct(shadowdir, shadowforward, shadowright);
5455 VectorM(scale, shadowright, &m[4]);
5456 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
5457 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
5458 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
5459 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
5460 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
5461 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);
5462 R_SetViewport(&viewport);
5464 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5466 // render into a slightly restricted region so that the borders of the
5467 // shadowmap area fade away, rather than streaking across everything
5468 // outside the usable area
5469 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
5471 for (i = 0;i < r_shadow_nummodelshadows;i++)
5473 ent = r_shadow_modelshadows[i];
5474 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5475 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
5476 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5477 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
5478 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
5479 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5480 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5481 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5482 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5483 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5484 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5485 RSurf_ActiveModelEntity(ent, false, false, false);
5486 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
5487 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5493 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
5495 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
5497 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
5498 Cvar_SetValueQuick(&r_test, 0);
5503 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
5504 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
5505 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
5506 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
5507 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
5508 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
5510 switch (vid.renderpath)
5512 case RENDERPATH_GL11:
5513 case RENDERPATH_GL13:
5514 case RENDERPATH_GL20:
5515 case RENDERPATH_SOFT:
5516 case RENDERPATH_GLES1:
5517 case RENDERPATH_GLES2:
5519 case RENDERPATH_D3D9:
5520 case RENDERPATH_D3D10:
5521 case RENDERPATH_D3D11:
5522 #ifdef MATRIX4x4_OPENGLORIENTATION
5523 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5524 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
5525 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
5526 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
5528 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5529 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
5530 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
5531 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
5537 void R_Shadow_DrawModelShadows(void)
5540 float relativethrowdistance;
5541 entity_render_t *ent;
5542 vec3_t relativelightorigin;
5543 vec3_t relativelightdirection;
5544 vec3_t relativeshadowmins, relativeshadowmaxs;
5545 vec3_t tmp, shadowdir;
5546 prvm_vec3_t prvmshadowdir;
5548 if (!r_shadow_nummodelshadows || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
5551 R_ResetViewRendering3D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5552 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
5553 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5554 R_Shadow_RenderMode_Begin();
5555 R_Shadow_RenderMode_ActiveLight(NULL);
5556 r_shadow_lightscissor[0] = r_refdef.view.x;
5557 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
5558 r_shadow_lightscissor[2] = r_refdef.view.width;
5559 r_shadow_lightscissor[3] = r_refdef.view.height;
5560 R_Shadow_RenderMode_StencilShadowVolumes(false);
5563 if (r_shadows.integer == 2)
5565 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5566 VectorCopy(prvmshadowdir, shadowdir);
5567 VectorNormalize(shadowdir);
5570 R_Shadow_ClearStencil();
5572 for (i = 0;i < r_shadow_nummodelshadows;i++)
5574 ent = r_shadow_modelshadows[i];
5576 // cast shadows from anything of the map (submodels are optional)
5577 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5578 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
5579 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
5580 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
5581 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5584 if(ent->entitynumber != 0)
5586 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
5588 // FIXME handle this
5589 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5593 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
5594 int entnum, entnum2, recursion;
5595 entnum = entnum2 = ent->entitynumber;
5596 for(recursion = 32; recursion > 0; --recursion)
5598 entnum2 = cl.entities[entnum].state_current.tagentity;
5599 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
5604 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
5606 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
5607 // transform into modelspace of OUR entity
5608 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
5609 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
5612 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5616 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5619 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
5620 RSurf_ActiveModelEntity(ent, false, false, false);
5621 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
5622 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5625 // not really the right mode, but this will disable any silly stencil features
5626 R_Shadow_RenderMode_End();
5628 // set up ortho view for rendering this pass
5629 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5630 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5631 //GL_ScissorTest(true);
5632 //R_EntityMatrix(&identitymatrix);
5633 //R_Mesh_ResetTextureState();
5634 R_ResetViewRendering2D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5636 // set up a darkening blend on shadowed areas
5637 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5638 //GL_DepthRange(0, 1);
5639 //GL_DepthTest(false);
5640 //GL_DepthMask(false);
5641 //GL_PolygonOffset(0, 0);CHECKGLERROR
5642 GL_Color(0, 0, 0, r_shadows_darken.value);
5643 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5644 //GL_DepthFunc(GL_ALWAYS);
5645 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5647 // apply the blend to the shadowed areas
5648 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5649 R_SetupShader_Generic_NoTexture(false, true);
5650 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5652 // restore the viewport
5653 R_SetViewport(&r_refdef.view.viewport);
5655 // restore other state to normal
5656 //R_Shadow_RenderMode_End();
5659 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5662 vec3_t centerorigin;
5663 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5666 // if it's too close, skip it
5667 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5669 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5672 if (usequery && r_numqueries + 2 <= r_maxqueries)
5674 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5675 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5676 // 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
5677 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5679 switch(vid.renderpath)
5681 case RENDERPATH_GL11:
5682 case RENDERPATH_GL13:
5683 case RENDERPATH_GL20:
5684 case RENDERPATH_GLES1:
5685 case RENDERPATH_GLES2:
5686 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5688 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5689 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5690 GL_DepthFunc(GL_ALWAYS);
5691 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5692 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5693 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5694 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5695 GL_DepthFunc(GL_LEQUAL);
5696 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5697 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5698 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5699 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5700 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5704 case RENDERPATH_D3D9:
5705 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5707 case RENDERPATH_D3D10:
5708 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5710 case RENDERPATH_D3D11:
5711 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5713 case RENDERPATH_SOFT:
5714 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5718 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5721 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5723 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5726 unsigned int occlude = 0;
5727 GLint allpixels = 0, visiblepixels = 0;
5729 // now we have to check the query result
5730 if (rtlight->corona_queryindex_visiblepixels)
5732 switch(vid.renderpath)
5734 case RENDERPATH_GL11:
5735 case RENDERPATH_GL13:
5736 case RENDERPATH_GL20:
5737 case RENDERPATH_GLES1:
5738 case RENDERPATH_GLES2:
5739 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5741 // See if we can use the GPU-side method to prevent implicit sync
5742 if (vid.support.arb_query_buffer_object) {
5743 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
5744 if (!r_shadow_occlusion_buf) {
5745 qglGenBuffersARB(1, &r_shadow_occlusion_buf);
5746 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5747 qglBufferDataARB(GL_QUERY_BUFFER_ARB, 8, NULL, GL_DYNAMIC_COPY);
5749 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5751 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(0));
5752 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4));
5753 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
5754 occlude = MATERIALFLAG_OCCLUDE;
5756 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5757 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5758 if (visiblepixels < 1 || allpixels < 1)
5760 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5762 cscale *= rtlight->corona_visibility;
5768 case RENDERPATH_D3D9:
5769 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5771 case RENDERPATH_D3D10:
5772 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5774 case RENDERPATH_D3D11:
5775 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5777 case RENDERPATH_SOFT:
5778 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5786 // FIXME: these traces should scan all render entities instead of cl.world
5787 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)
5790 VectorScale(rtlight->currentcolor, cscale, color);
5791 if (VectorLength(color) > (1.0f / 256.0f))
5794 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
5797 VectorNegate(color, color);
5798 GL_BlendEquationSubtract(true);
5800 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5801 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);
5802 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
5804 GL_BlendEquationSubtract(false);
5808 void R_Shadow_DrawCoronas(void)
5811 qboolean usequery = false;
5816 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
5818 if (r_fb.water.renderingscene)
5820 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5821 R_EntityMatrix(&identitymatrix);
5823 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5825 // check occlusion of coronas
5826 // use GL_ARB_occlusion_query if available
5827 // otherwise use raytraces
5829 switch (vid.renderpath)
5831 case RENDERPATH_GL11:
5832 case RENDERPATH_GL13:
5833 case RENDERPATH_GL20:
5834 case RENDERPATH_GLES1:
5835 case RENDERPATH_GLES2:
5836 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
5837 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5840 GL_ColorMask(0,0,0,0);
5841 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
5842 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
5845 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
5846 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
5848 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
5851 RSurf_ActiveWorldEntity();
5852 GL_BlendFunc(GL_ONE, GL_ZERO);
5853 GL_CullFace(GL_NONE);
5854 GL_DepthMask(false);
5855 GL_DepthRange(0, 1);
5856 GL_PolygonOffset(0, 0);
5858 R_Mesh_ResetTextureState();
5859 R_SetupShader_Generic_NoTexture(false, false);
5863 case RENDERPATH_D3D9:
5865 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5867 case RENDERPATH_D3D10:
5868 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5870 case RENDERPATH_D3D11:
5871 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5873 case RENDERPATH_SOFT:
5875 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5878 for (lightindex = 0;lightindex < range;lightindex++)
5880 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5883 rtlight = &light->rtlight;
5884 rtlight->corona_visibility = 0;
5885 rtlight->corona_queryindex_visiblepixels = 0;
5886 rtlight->corona_queryindex_allpixels = 0;
5887 if (!(rtlight->flags & flag))
5889 if (rtlight->corona <= 0)
5891 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
5893 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5895 for (i = 0;i < r_refdef.scene.numlights;i++)
5897 rtlight = r_refdef.scene.lights[i];
5898 rtlight->corona_visibility = 0;
5899 rtlight->corona_queryindex_visiblepixels = 0;
5900 rtlight->corona_queryindex_allpixels = 0;
5901 if (!(rtlight->flags & flag))
5903 if (rtlight->corona <= 0)
5905 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5908 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5910 // now draw the coronas using the query data for intensity info
5911 for (lightindex = 0;lightindex < range;lightindex++)
5913 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5916 rtlight = &light->rtlight;
5917 if (rtlight->corona_visibility <= 0)
5919 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5921 for (i = 0;i < r_refdef.scene.numlights;i++)
5923 rtlight = r_refdef.scene.lights[i];
5924 if (rtlight->corona_visibility <= 0)
5926 if (gl_flashblend.integer)
5927 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
5929 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5935 static dlight_t *R_Shadow_NewWorldLight(void)
5937 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
5940 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)
5944 // 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
5946 // validate parameters
5950 // copy to light properties
5951 VectorCopy(origin, light->origin);
5952 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
5953 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
5954 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
5956 light->color[0] = max(color[0], 0);
5957 light->color[1] = max(color[1], 0);
5958 light->color[2] = max(color[2], 0);
5960 light->color[0] = color[0];
5961 light->color[1] = color[1];
5962 light->color[2] = color[2];
5963 light->radius = max(radius, 0);
5964 light->style = style;
5965 light->shadow = shadowenable;
5966 light->corona = corona;
5967 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
5968 light->coronasizescale = coronasizescale;
5969 light->ambientscale = ambientscale;
5970 light->diffusescale = diffusescale;
5971 light->specularscale = specularscale;
5972 light->flags = flags;
5974 // update renderable light data
5975 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
5976 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);
5979 static void R_Shadow_FreeWorldLight(dlight_t *light)
5981 if (r_shadow_selectedlight == light)
5982 r_shadow_selectedlight = NULL;
5983 R_RTLight_Uncompile(&light->rtlight);
5984 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
5987 void R_Shadow_ClearWorldLights(void)
5991 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5992 for (lightindex = 0;lightindex < range;lightindex++)
5994 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5996 R_Shadow_FreeWorldLight(light);
5998 r_shadow_selectedlight = NULL;
6001 static void R_Shadow_SelectLight(dlight_t *light)
6003 if (r_shadow_selectedlight)
6004 r_shadow_selectedlight->selected = false;
6005 r_shadow_selectedlight = light;
6006 if (r_shadow_selectedlight)
6007 r_shadow_selectedlight->selected = true;
6010 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6012 // this is never batched (there can be only one)
6014 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
6015 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6016 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6019 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6024 skinframe_t *skinframe;
6027 // this is never batched (due to the ent parameter changing every time)
6028 // so numsurfaces == 1 and surfacelist[0] == lightnumber
6029 const dlight_t *light = (dlight_t *)ent;
6032 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
6035 VectorScale(light->color, intensity, spritecolor);
6036 if (VectorLength(spritecolor) < 0.1732f)
6037 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
6038 if (VectorLength(spritecolor) > 1.0f)
6039 VectorNormalize(spritecolor);
6041 // draw light sprite
6042 if (light->cubemapname[0] && !light->shadow)
6043 skinframe = r_editlights_sprcubemapnoshadowlight;
6044 else if (light->cubemapname[0])
6045 skinframe = r_editlights_sprcubemaplight;
6046 else if (!light->shadow)
6047 skinframe = r_editlights_sprnoshadowlight;
6049 skinframe = r_editlights_sprlight;
6051 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);
6052 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6054 // draw selection sprite if light is selected
6055 if (light->selected)
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_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6059 // VorteX todo: add normalmode/realtime mode light overlay sprites?
6063 void R_Shadow_DrawLightSprites(void)
6067 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6068 for (lightindex = 0;lightindex < range;lightindex++)
6070 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6072 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
6074 if (!r_editlights_lockcursor)
6075 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
6078 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
6083 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6084 if (lightindex >= range)
6086 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6089 rtlight = &light->rtlight;
6090 //if (!(rtlight->flags & flag))
6092 VectorCopy(rtlight->shadoworigin, origin);
6093 *radius = rtlight->radius;
6094 VectorCopy(rtlight->color, color);
6098 static void R_Shadow_SelectLightInView(void)
6100 float bestrating, rating, temp[3];
6104 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6108 if (r_editlights_lockcursor)
6110 for (lightindex = 0;lightindex < range;lightindex++)
6112 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6115 VectorSubtract(light->origin, r_refdef.view.origin, temp);
6116 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
6119 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
6120 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)
6122 bestrating = rating;
6127 R_Shadow_SelectLight(best);
6130 void R_Shadow_LoadWorldLights(void)
6132 int n, a, style, shadow, flags;
6133 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
6134 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
6135 if (cl.worldmodel == NULL)
6137 Con_Print("No map loaded.\n");
6140 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6141 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6151 for (;COM_Parse(t, true) && strcmp(
6152 if (COM_Parse(t, true))
6154 if (com_token[0] == '!')
6157 origin[0] = atof(com_token+1);
6160 origin[0] = atof(com_token);
6165 while (*s && *s != '\n' && *s != '\r')
6171 // check for modifier flags
6178 #if _MSC_VER >= 1400
6179 #define sscanf sscanf_s
6181 cubemapname[sizeof(cubemapname)-1] = 0;
6182 #if MAX_QPATH != 128
6183 #error update this code if MAX_QPATH changes
6185 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
6186 #if _MSC_VER >= 1400
6187 , sizeof(cubemapname)
6189 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
6192 flags = LIGHTFLAG_REALTIMEMODE;
6200 coronasizescale = 0.25f;
6202 VectorClear(angles);
6205 if (a < 9 || !strcmp(cubemapname, "\"\""))
6207 // remove quotes on cubemapname
6208 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
6211 namelen = strlen(cubemapname) - 2;
6212 memmove(cubemapname, cubemapname + 1, namelen);
6213 cubemapname[namelen] = '\0';
6217 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);
6220 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6228 Con_Printf("invalid rtlights file \"%s\"\n", name);
6229 Mem_Free(lightsstring);
6233 void R_Shadow_SaveWorldLights(void)
6237 size_t bufchars, bufmaxchars;
6239 char name[MAX_QPATH];
6240 char line[MAX_INPUTLINE];
6241 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
6242 // I hate lines which are 3 times my screen size :( --blub
6245 if (cl.worldmodel == NULL)
6247 Con_Print("No map loaded.\n");
6250 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6251 bufchars = bufmaxchars = 0;
6253 for (lightindex = 0;lightindex < range;lightindex++)
6255 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6258 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
6259 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);
6260 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
6261 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]);
6263 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);
6264 if (bufchars + strlen(line) > bufmaxchars)
6266 bufmaxchars = bufchars + strlen(line) + 2048;
6268 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
6272 memcpy(buf, oldbuf, bufchars);
6278 memcpy(buf + bufchars, line, strlen(line));
6279 bufchars += strlen(line);
6283 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
6288 void R_Shadow_LoadLightsFile(void)
6291 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
6292 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
6293 if (cl.worldmodel == NULL)
6295 Con_Print("No map loaded.\n");
6298 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
6299 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6307 while (*s && *s != '\n' && *s != '\r')
6313 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);
6317 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);
6320 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
6321 radius = bound(15, radius, 4096);
6322 VectorScale(color, (2.0f / (8388608.0f)), color);
6323 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6331 Con_Printf("invalid lights file \"%s\"\n", name);
6332 Mem_Free(lightsstring);
6336 // tyrlite/hmap2 light types in the delay field
6337 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
6339 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
6351 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
6352 char key[256], value[MAX_INPUTLINE];
6355 if (cl.worldmodel == NULL)
6357 Con_Print("No map loaded.\n");
6360 // try to load a .ent file first
6361 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
6362 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
6363 // and if that is not found, fall back to the bsp file entity string
6365 data = cl.worldmodel->brush.entities;
6368 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
6370 type = LIGHTTYPE_MINUSX;
6371 origin[0] = origin[1] = origin[2] = 0;
6372 originhack[0] = originhack[1] = originhack[2] = 0;
6373 angles[0] = angles[1] = angles[2] = 0;
6374 color[0] = color[1] = color[2] = 1;
6375 light[0] = light[1] = light[2] = 1;light[3] = 300;
6376 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
6386 if (!COM_ParseToken_Simple(&data, false, false, true))
6388 if (com_token[0] == '}')
6389 break; // end of entity
6390 if (com_token[0] == '_')
6391 strlcpy(key, com_token + 1, sizeof(key));
6393 strlcpy(key, com_token, sizeof(key));
6394 while (key[strlen(key)-1] == ' ') // remove trailing spaces
6395 key[strlen(key)-1] = 0;
6396 if (!COM_ParseToken_Simple(&data, false, false, true))
6398 strlcpy(value, com_token, sizeof(value));
6400 // now that we have the key pair worked out...
6401 if (!strcmp("light", key))
6403 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
6407 light[0] = vec[0] * (1.0f / 256.0f);
6408 light[1] = vec[0] * (1.0f / 256.0f);
6409 light[2] = vec[0] * (1.0f / 256.0f);
6415 light[0] = vec[0] * (1.0f / 255.0f);
6416 light[1] = vec[1] * (1.0f / 255.0f);
6417 light[2] = vec[2] * (1.0f / 255.0f);
6421 else if (!strcmp("delay", key))
6423 else if (!strcmp("origin", key))
6424 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
6425 else if (!strcmp("angle", key))
6426 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
6427 else if (!strcmp("angles", key))
6428 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
6429 else if (!strcmp("color", key))
6430 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
6431 else if (!strcmp("wait", key))
6432 fadescale = atof(value);
6433 else if (!strcmp("classname", key))
6435 if (!strncmp(value, "light", 5))
6438 if (!strcmp(value, "light_fluoro"))
6443 overridecolor[0] = 1;
6444 overridecolor[1] = 1;
6445 overridecolor[2] = 1;
6447 if (!strcmp(value, "light_fluorospark"))
6452 overridecolor[0] = 1;
6453 overridecolor[1] = 1;
6454 overridecolor[2] = 1;
6456 if (!strcmp(value, "light_globe"))
6461 overridecolor[0] = 1;
6462 overridecolor[1] = 0.8;
6463 overridecolor[2] = 0.4;
6465 if (!strcmp(value, "light_flame_large_yellow"))
6470 overridecolor[0] = 1;
6471 overridecolor[1] = 0.5;
6472 overridecolor[2] = 0.1;
6474 if (!strcmp(value, "light_flame_small_yellow"))
6479 overridecolor[0] = 1;
6480 overridecolor[1] = 0.5;
6481 overridecolor[2] = 0.1;
6483 if (!strcmp(value, "light_torch_small_white"))
6488 overridecolor[0] = 1;
6489 overridecolor[1] = 0.5;
6490 overridecolor[2] = 0.1;
6492 if (!strcmp(value, "light_torch_small_walltorch"))
6497 overridecolor[0] = 1;
6498 overridecolor[1] = 0.5;
6499 overridecolor[2] = 0.1;
6503 else if (!strcmp("style", key))
6504 style = atoi(value);
6505 else if (!strcmp("skin", key))
6506 skin = (int)atof(value);
6507 else if (!strcmp("pflags", key))
6508 pflags = (int)atof(value);
6509 //else if (!strcmp("effects", key))
6510 // effects = (int)atof(value);
6511 else if (cl.worldmodel->type == mod_brushq3)
6513 if (!strcmp("scale", key))
6514 lightscale = atof(value);
6515 if (!strcmp("fade", key))
6516 fadescale = atof(value);
6521 if (lightscale <= 0)
6525 if (color[0] == color[1] && color[0] == color[2])
6527 color[0] *= overridecolor[0];
6528 color[1] *= overridecolor[1];
6529 color[2] *= overridecolor[2];
6531 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
6532 color[0] = color[0] * light[0];
6533 color[1] = color[1] * light[1];
6534 color[2] = color[2] * light[2];
6537 case LIGHTTYPE_MINUSX:
6539 case LIGHTTYPE_RECIPX:
6541 VectorScale(color, (1.0f / 16.0f), color);
6543 case LIGHTTYPE_RECIPXX:
6545 VectorScale(color, (1.0f / 16.0f), color);
6548 case LIGHTTYPE_NONE:
6552 case LIGHTTYPE_MINUSXX:
6555 VectorAdd(origin, originhack, origin);
6557 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);
6560 Mem_Free(entfiledata);
6564 static void R_Shadow_SetCursorLocationForView(void)
6567 vec3_t dest, endpos;
6569 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
6570 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true);
6571 if (trace.fraction < 1)
6573 dist = trace.fraction * r_editlights_cursordistance.value;
6574 push = r_editlights_cursorpushback.value;
6578 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
6579 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
6583 VectorClear( endpos );
6585 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6586 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6587 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6590 void R_Shadow_UpdateWorldLightSelection(void)
6592 if (r_editlights.integer)
6594 R_Shadow_SetCursorLocationForView();
6595 R_Shadow_SelectLightInView();
6598 R_Shadow_SelectLight(NULL);
6601 static void R_Shadow_EditLights_Clear_f(void)
6603 R_Shadow_ClearWorldLights();
6606 void R_Shadow_EditLights_Reload_f(void)
6610 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
6611 R_Shadow_ClearWorldLights();
6612 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
6614 R_Shadow_LoadWorldLights();
6615 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6616 R_Shadow_LoadLightsFile();
6618 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
6620 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6621 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6625 static void R_Shadow_EditLights_Save_f(void)
6629 R_Shadow_SaveWorldLights();
6632 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6634 R_Shadow_ClearWorldLights();
6635 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6638 static void R_Shadow_EditLights_ImportLightsFile_f(void)
6640 R_Shadow_ClearWorldLights();
6641 R_Shadow_LoadLightsFile();
6644 static void R_Shadow_EditLights_Spawn_f(void)
6647 if (!r_editlights.integer)
6649 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6652 if (Cmd_Argc() != 1)
6654 Con_Print("r_editlights_spawn does not take parameters\n");
6657 color[0] = color[1] = color[2] = 1;
6658 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6661 static void R_Shadow_EditLights_Edit_f(void)
6663 vec3_t origin, angles, color;
6664 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6665 int style, shadows, flags, normalmode, realtimemode;
6666 char cubemapname[MAX_INPUTLINE];
6667 if (!r_editlights.integer)
6669 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6672 if (!r_shadow_selectedlight)
6674 Con_Print("No selected light.\n");
6677 VectorCopy(r_shadow_selectedlight->origin, origin);
6678 VectorCopy(r_shadow_selectedlight->angles, angles);
6679 VectorCopy(r_shadow_selectedlight->color, color);
6680 radius = r_shadow_selectedlight->radius;
6681 style = r_shadow_selectedlight->style;
6682 if (r_shadow_selectedlight->cubemapname)
6683 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6686 shadows = r_shadow_selectedlight->shadow;
6687 corona = r_shadow_selectedlight->corona;
6688 coronasizescale = r_shadow_selectedlight->coronasizescale;
6689 ambientscale = r_shadow_selectedlight->ambientscale;
6690 diffusescale = r_shadow_selectedlight->diffusescale;
6691 specularscale = r_shadow_selectedlight->specularscale;
6692 flags = r_shadow_selectedlight->flags;
6693 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6694 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6695 if (!strcmp(Cmd_Argv(1), "origin"))
6697 if (Cmd_Argc() != 5)
6699 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6702 origin[0] = atof(Cmd_Argv(2));
6703 origin[1] = atof(Cmd_Argv(3));
6704 origin[2] = atof(Cmd_Argv(4));
6706 else if (!strcmp(Cmd_Argv(1), "originscale"))
6708 if (Cmd_Argc() != 5)
6710 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6713 origin[0] *= atof(Cmd_Argv(2));
6714 origin[1] *= atof(Cmd_Argv(3));
6715 origin[2] *= atof(Cmd_Argv(4));
6717 else if (!strcmp(Cmd_Argv(1), "originx"))
6719 if (Cmd_Argc() != 3)
6721 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6724 origin[0] = atof(Cmd_Argv(2));
6726 else if (!strcmp(Cmd_Argv(1), "originy"))
6728 if (Cmd_Argc() != 3)
6730 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6733 origin[1] = atof(Cmd_Argv(2));
6735 else if (!strcmp(Cmd_Argv(1), "originz"))
6737 if (Cmd_Argc() != 3)
6739 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6742 origin[2] = atof(Cmd_Argv(2));
6744 else if (!strcmp(Cmd_Argv(1), "move"))
6746 if (Cmd_Argc() != 5)
6748 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6751 origin[0] += atof(Cmd_Argv(2));
6752 origin[1] += atof(Cmd_Argv(3));
6753 origin[2] += atof(Cmd_Argv(4));
6755 else if (!strcmp(Cmd_Argv(1), "movex"))
6757 if (Cmd_Argc() != 3)
6759 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6762 origin[0] += atof(Cmd_Argv(2));
6764 else if (!strcmp(Cmd_Argv(1), "movey"))
6766 if (Cmd_Argc() != 3)
6768 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6771 origin[1] += atof(Cmd_Argv(2));
6773 else if (!strcmp(Cmd_Argv(1), "movez"))
6775 if (Cmd_Argc() != 3)
6777 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6780 origin[2] += atof(Cmd_Argv(2));
6782 else if (!strcmp(Cmd_Argv(1), "angles"))
6784 if (Cmd_Argc() != 5)
6786 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6789 angles[0] = atof(Cmd_Argv(2));
6790 angles[1] = atof(Cmd_Argv(3));
6791 angles[2] = atof(Cmd_Argv(4));
6793 else if (!strcmp(Cmd_Argv(1), "anglesx"))
6795 if (Cmd_Argc() != 3)
6797 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6800 angles[0] = atof(Cmd_Argv(2));
6802 else if (!strcmp(Cmd_Argv(1), "anglesy"))
6804 if (Cmd_Argc() != 3)
6806 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6809 angles[1] = atof(Cmd_Argv(2));
6811 else if (!strcmp(Cmd_Argv(1), "anglesz"))
6813 if (Cmd_Argc() != 3)
6815 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6818 angles[2] = atof(Cmd_Argv(2));
6820 else if (!strcmp(Cmd_Argv(1), "color"))
6822 if (Cmd_Argc() != 5)
6824 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
6827 color[0] = atof(Cmd_Argv(2));
6828 color[1] = atof(Cmd_Argv(3));
6829 color[2] = atof(Cmd_Argv(4));
6831 else if (!strcmp(Cmd_Argv(1), "radius"))
6833 if (Cmd_Argc() != 3)
6835 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6838 radius = atof(Cmd_Argv(2));
6840 else if (!strcmp(Cmd_Argv(1), "colorscale"))
6842 if (Cmd_Argc() == 3)
6844 double scale = atof(Cmd_Argv(2));
6851 if (Cmd_Argc() != 5)
6853 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
6856 color[0] *= atof(Cmd_Argv(2));
6857 color[1] *= atof(Cmd_Argv(3));
6858 color[2] *= atof(Cmd_Argv(4));
6861 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
6863 if (Cmd_Argc() != 3)
6865 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6868 radius *= atof(Cmd_Argv(2));
6870 else if (!strcmp(Cmd_Argv(1), "style"))
6872 if (Cmd_Argc() != 3)
6874 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6877 style = atoi(Cmd_Argv(2));
6879 else if (!strcmp(Cmd_Argv(1), "cubemap"))
6883 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6886 if (Cmd_Argc() == 3)
6887 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
6891 else if (!strcmp(Cmd_Argv(1), "shadows"))
6893 if (Cmd_Argc() != 3)
6895 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6898 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6900 else if (!strcmp(Cmd_Argv(1), "corona"))
6902 if (Cmd_Argc() != 3)
6904 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6907 corona = atof(Cmd_Argv(2));
6909 else if (!strcmp(Cmd_Argv(1), "coronasize"))
6911 if (Cmd_Argc() != 3)
6913 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6916 coronasizescale = atof(Cmd_Argv(2));
6918 else if (!strcmp(Cmd_Argv(1), "ambient"))
6920 if (Cmd_Argc() != 3)
6922 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6925 ambientscale = atof(Cmd_Argv(2));
6927 else if (!strcmp(Cmd_Argv(1), "diffuse"))
6929 if (Cmd_Argc() != 3)
6931 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6934 diffusescale = atof(Cmd_Argv(2));
6936 else if (!strcmp(Cmd_Argv(1), "specular"))
6938 if (Cmd_Argc() != 3)
6940 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6943 specularscale = atof(Cmd_Argv(2));
6945 else if (!strcmp(Cmd_Argv(1), "normalmode"))
6947 if (Cmd_Argc() != 3)
6949 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6952 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6954 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
6956 if (Cmd_Argc() != 3)
6958 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6961 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6965 Con_Print("usage: r_editlights_edit [property] [value]\n");
6966 Con_Print("Selected light's properties:\n");
6967 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6968 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6969 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6970 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
6971 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
6972 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
6973 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
6974 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
6975 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
6976 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
6977 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
6978 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
6979 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
6980 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
6983 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
6984 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6987 static void R_Shadow_EditLights_EditAll_f(void)
6990 dlight_t *light, *oldselected;
6993 if (!r_editlights.integer)
6995 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
6999 oldselected = r_shadow_selectedlight;
7000 // EditLights doesn't seem to have a "remove" command or something so:
7001 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7002 for (lightindex = 0;lightindex < range;lightindex++)
7004 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7007 R_Shadow_SelectLight(light);
7008 R_Shadow_EditLights_Edit_f();
7010 // return to old selected (to not mess editing once selection is locked)
7011 R_Shadow_SelectLight(oldselected);
7014 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
7016 int lightnumber, lightcount;
7017 size_t lightindex, range;
7022 if (!r_editlights.integer)
7025 // update cvars so QC can query them
7026 if (r_shadow_selectedlight)
7028 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7029 Cvar_SetQuick(&r_editlights_current_origin, temp);
7030 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7031 Cvar_SetQuick(&r_editlights_current_angles, temp);
7032 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7033 Cvar_SetQuick(&r_editlights_current_color, temp);
7034 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
7035 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
7036 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
7037 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
7038 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
7039 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
7040 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
7041 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
7042 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
7043 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
7044 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
7047 // draw properties on screen
7048 if (!r_editlights_drawproperties.integer)
7050 x = vid_conwidth.value - 240;
7052 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
7055 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7056 for (lightindex = 0;lightindex < range;lightindex++)
7058 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7061 if (light == r_shadow_selectedlight)
7062 lightnumber = (int)lightindex;
7065 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;
7066 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;
7068 if (r_shadow_selectedlight == NULL)
7070 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;
7071 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;
7072 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;
7073 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;
7074 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;
7075 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;
7076 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;
7077 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;
7078 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;
7079 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;
7080 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;
7081 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;
7082 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;
7083 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;
7084 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;
7087 static void R_Shadow_EditLights_ToggleShadow_f(void)
7089 if (!r_editlights.integer)
7091 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7094 if (!r_shadow_selectedlight)
7096 Con_Print("No selected light.\n");
7099 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);
7102 static void R_Shadow_EditLights_ToggleCorona_f(void)
7104 if (!r_editlights.integer)
7106 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7109 if (!r_shadow_selectedlight)
7111 Con_Print("No selected light.\n");
7114 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);
7117 static void R_Shadow_EditLights_Remove_f(void)
7119 if (!r_editlights.integer)
7121 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
7124 if (!r_shadow_selectedlight)
7126 Con_Print("No selected light.\n");
7129 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
7130 r_shadow_selectedlight = NULL;
7133 static void R_Shadow_EditLights_Help_f(void)
7136 "Documentation on r_editlights system:\n"
7138 "r_editlights : enable/disable editing mode\n"
7139 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
7140 "r_editlights_cursorpushback : push back cursor this far from surface\n"
7141 "r_editlights_cursorpushoff : push cursor off surface this far\n"
7142 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
7143 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
7145 "r_editlights_help : this help\n"
7146 "r_editlights_clear : remove all lights\n"
7147 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
7148 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
7149 "r_editlights_save : save to .rtlights file\n"
7150 "r_editlights_spawn : create a light with default settings\n"
7151 "r_editlights_edit command : edit selected light - more documentation below\n"
7152 "r_editlights_remove : remove selected light\n"
7153 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
7154 "r_editlights_importlightentitiesfrommap : reload light entities\n"
7155 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
7157 "origin x y z : set light location\n"
7158 "originx x: set x component of light location\n"
7159 "originy y: set y component of light location\n"
7160 "originz z: set z component of light location\n"
7161 "move x y z : adjust light location\n"
7162 "movex x: adjust x component of light location\n"
7163 "movey y: adjust y component of light location\n"
7164 "movez z: adjust z component of light location\n"
7165 "angles x y z : set light angles\n"
7166 "anglesx x: set x component of light angles\n"
7167 "anglesy y: set y component of light angles\n"
7168 "anglesz z: set z component of light angles\n"
7169 "color r g b : set color of light (can be brighter than 1 1 1)\n"
7170 "radius radius : set radius (size) of light\n"
7171 "colorscale grey : multiply color of light (1 does nothing)\n"
7172 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
7173 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
7174 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
7175 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
7176 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
7177 "cubemap basename : set filter cubemap of light\n"
7178 "shadows 1/0 : turn on/off shadows\n"
7179 "corona n : set corona intensity\n"
7180 "coronasize n : set corona size (0-1)\n"
7181 "ambient n : set ambient intensity (0-1)\n"
7182 "diffuse n : set diffuse intensity (0-1)\n"
7183 "specular n : set specular intensity (0-1)\n"
7184 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
7185 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
7186 "<nothing> : print light properties to console\n"
7190 static void R_Shadow_EditLights_CopyInfo_f(void)
7192 if (!r_editlights.integer)
7194 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
7197 if (!r_shadow_selectedlight)
7199 Con_Print("No selected light.\n");
7202 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
7203 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
7204 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
7205 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
7206 if (r_shadow_selectedlight->cubemapname)
7207 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
7209 r_shadow_bufferlight.cubemapname[0] = 0;
7210 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
7211 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
7212 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
7213 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
7214 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
7215 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
7216 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
7219 static void R_Shadow_EditLights_PasteInfo_f(void)
7221 if (!r_editlights.integer)
7223 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
7226 if (!r_shadow_selectedlight)
7228 Con_Print("No selected light.\n");
7231 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);
7234 static void R_Shadow_EditLights_Lock_f(void)
7236 if (!r_editlights.integer)
7238 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
7241 if (r_editlights_lockcursor)
7243 r_editlights_lockcursor = false;
7246 if (!r_shadow_selectedlight)
7248 Con_Print("No selected light to lock on.\n");
7251 r_editlights_lockcursor = true;
7254 static void R_Shadow_EditLights_Init(void)
7256 Cvar_RegisterVariable(&r_editlights);
7257 Cvar_RegisterVariable(&r_editlights_cursordistance);
7258 Cvar_RegisterVariable(&r_editlights_cursorpushback);
7259 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
7260 Cvar_RegisterVariable(&r_editlights_cursorgrid);
7261 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
7262 Cvar_RegisterVariable(&r_editlights_drawproperties);
7263 Cvar_RegisterVariable(&r_editlights_current_origin);
7264 Cvar_RegisterVariable(&r_editlights_current_angles);
7265 Cvar_RegisterVariable(&r_editlights_current_color);
7266 Cvar_RegisterVariable(&r_editlights_current_radius);
7267 Cvar_RegisterVariable(&r_editlights_current_corona);
7268 Cvar_RegisterVariable(&r_editlights_current_coronasize);
7269 Cvar_RegisterVariable(&r_editlights_current_style);
7270 Cvar_RegisterVariable(&r_editlights_current_shadows);
7271 Cvar_RegisterVariable(&r_editlights_current_cubemap);
7272 Cvar_RegisterVariable(&r_editlights_current_ambient);
7273 Cvar_RegisterVariable(&r_editlights_current_diffuse);
7274 Cvar_RegisterVariable(&r_editlights_current_specular);
7275 Cvar_RegisterVariable(&r_editlights_current_normalmode);
7276 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
7277 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
7278 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
7279 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)");
7280 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
7281 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
7282 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
7283 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)");
7284 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
7285 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
7286 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
7287 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
7288 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
7289 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
7290 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)");
7291 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
7297 =============================================================================
7301 =============================================================================
7304 void R_LightPoint(float *color, const vec3_t p, const int flags)
7306 int i, numlights, flag;
7307 float f, relativepoint[3], dist, dist2, lightradius2;
7312 if (r_fullbright.integer)
7314 VectorSet(color, 1, 1, 1);
7320 if (flags & LP_LIGHTMAP)
7322 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7324 VectorClear(diffuse);
7325 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, color, diffuse, n);
7326 VectorAdd(color, diffuse, color);
7329 VectorSet(color, 1, 1, 1);
7330 color[0] += r_refdef.scene.ambient;
7331 color[1] += r_refdef.scene.ambient;
7332 color[2] += r_refdef.scene.ambient;
7335 if (flags & LP_RTWORLD)
7337 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7338 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7339 for (i = 0; i < numlights; i++)
7341 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7344 light = &dlight->rtlight;
7345 if (!(light->flags & flag))
7348 lightradius2 = light->radius * light->radius;
7349 VectorSubtract(light->shadoworigin, p, relativepoint);
7350 dist2 = VectorLength2(relativepoint);
7351 if (dist2 >= lightradius2)
7353 dist = sqrt(dist2) / light->radius;
7354 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7357 // todo: add to both ambient and diffuse
7358 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)
7359 VectorMA(color, f, light->currentcolor, color);
7362 if (flags & LP_DYNLIGHT)
7365 for (i = 0;i < r_refdef.scene.numlights;i++)
7367 light = r_refdef.scene.lights[i];
7369 lightradius2 = light->radius * light->radius;
7370 VectorSubtract(light->shadoworigin, p, relativepoint);
7371 dist2 = VectorLength2(relativepoint);
7372 if (dist2 >= lightradius2)
7374 dist = sqrt(dist2) / light->radius;
7375 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7378 // todo: add to both ambient and diffuse
7379 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)
7380 VectorMA(color, f, light->color, color);
7385 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
7387 int i, numlights, flag;
7390 float relativepoint[3];
7399 if (r_fullbright.integer)
7401 VectorSet(ambient, 1, 1, 1);
7402 VectorClear(diffuse);
7403 VectorClear(lightdir);
7407 if (flags == LP_LIGHTMAP)
7409 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7410 VectorClear(diffuse);
7411 VectorClear(lightdir);
7412 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7413 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
7415 VectorSet(ambient, 1, 1, 1);
7419 memset(sample, 0, sizeof(sample));
7420 VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7422 if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7425 VectorClear(tempambient);
7427 VectorClear(relativepoint);
7428 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
7429 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
7430 VectorScale(color, r_refdef.lightmapintensity, color);
7431 VectorAdd(sample, tempambient, sample);
7432 VectorMA(sample , 0.5f , color, sample );
7433 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7434 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7435 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7436 // calculate a weighted average light direction as well
7437 intensity = VectorLength(color);
7438 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7441 if (flags & LP_RTWORLD)
7443 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7444 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7445 for (i = 0; i < numlights; i++)
7447 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7450 light = &dlight->rtlight;
7451 if (!(light->flags & flag))
7454 lightradius2 = light->radius * light->radius;
7455 VectorSubtract(light->shadoworigin, p, relativepoint);
7456 dist2 = VectorLength2(relativepoint);
7457 if (dist2 >= lightradius2)
7459 dist = sqrt(dist2) / light->radius;
7460 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
7461 if (intensity <= 0.0f)
7463 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)
7465 // scale down intensity to add to both ambient and diffuse
7466 //intensity *= 0.5f;
7467 VectorNormalize(relativepoint);
7468 VectorScale(light->currentcolor, intensity, color);
7469 VectorMA(sample , 0.5f , color, sample );
7470 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7471 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7472 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7473 // calculate a weighted average light direction as well
7474 intensity *= VectorLength(color);
7475 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7477 // FIXME: sample bouncegrid too!
7480 if (flags & LP_DYNLIGHT)
7483 for (i = 0;i < r_refdef.scene.numlights;i++)
7485 light = r_refdef.scene.lights[i];
7487 lightradius2 = light->radius * light->radius;
7488 VectorSubtract(light->shadoworigin, p, relativepoint);
7489 dist2 = VectorLength2(relativepoint);
7490 if (dist2 >= lightradius2)
7492 dist = sqrt(dist2) / light->radius;
7493 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
7494 if (intensity <= 0.0f)
7496 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)
7498 // scale down intensity to add to both ambient and diffuse
7499 //intensity *= 0.5f;
7500 VectorNormalize(relativepoint);
7501 VectorScale(light->currentcolor, intensity, color);
7502 VectorMA(sample , 0.5f , color, sample );
7503 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7504 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7505 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7506 // calculate a weighted average light direction as well
7507 intensity *= VectorLength(color);
7508 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7512 // calculate the direction we'll use to reduce the sample to a directional light source
7513 VectorCopy(sample + 12, dir);
7514 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
7515 VectorNormalize(dir);
7516 // extract the diffuse color along the chosen direction and scale it
7517 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
7518 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
7519 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
7520 // subtract some of diffuse from ambient
7521 VectorMA(sample, -0.333f, diffuse, ambient);
7522 // store the normalized lightdir
7523 VectorCopy(dir, lightdir);