3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however. Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light. This technique is used heavily in many games (Doom3 does not support
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
142 #include "dpsoftrast.h"
146 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
149 static void R_Shadow_EditLights_Init(void);
151 typedef enum r_shadow_rendermode_e
153 R_SHADOW_RENDERMODE_NONE,
154 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
155 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
156 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
157 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
158 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
159 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
160 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
161 R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN,
162 R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN,
163 R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN,
164 R_SHADOW_RENDERMODE_LIGHT_GLSL,
165 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
166 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
167 R_SHADOW_RENDERMODE_SHADOWMAP2D
169 r_shadow_rendermode_t;
171 typedef enum r_shadow_shadowmode_e
173 R_SHADOW_SHADOWMODE_STENCIL,
174 R_SHADOW_SHADOWMODE_SHADOWMAP2D
176 r_shadow_shadowmode_t;
178 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
180 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
181 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
182 int r_shadow_scenemaxlights;
183 int r_shadow_scenenumlights;
184 rtlight_t **r_shadow_scenelightlist; // includes both static lights and dlights, as filtered by appropriate flags
185 qboolean r_shadow_usingshadowmap2d;
186 qboolean r_shadow_usingshadowmaportho;
187 int r_shadow_shadowmapside;
188 float r_shadow_lightshadowmap_texturescale[4]; // xy = scale, zw = offset
189 float r_shadow_lightshadowmap_parameters[4]; // x = frustum width in pixels (excludes border), y = z scale, z = size of viewport, w = z center
190 float r_shadow_modelshadowmap_texturescale[4]; // xy = scale, zw = offset
191 float r_shadow_modelshadowmap_parameters[4]; // xyz = scale, w = shadow brightness
193 int r_shadow_drawbuffer;
194 int r_shadow_readbuffer;
196 int r_shadow_cullface_front, r_shadow_cullface_back;
197 GLuint r_shadow_fbo2d;
198 r_shadow_shadowmode_t r_shadow_shadowmode;
199 int r_shadow_shadowmapfilterquality;
200 int r_shadow_shadowmapdepthbits;
201 int r_shadow_shadowmapmaxsize;
202 int r_shadow_shadowmaptexturesize;
203 qboolean r_shadow_shadowmapvsdct;
204 qboolean r_shadow_shadowmapsampler;
205 qboolean r_shadow_shadowmapshadowsampler;
206 int r_shadow_shadowmappcf;
207 int r_shadow_shadowmapborder;
208 matrix4x4_t r_shadow_shadowmapmatrix;
209 int r_shadow_lightscissor[4];
210 qboolean r_shadow_usingdeferredprepass;
211 qboolean r_shadow_shadowmapdepthtexture;
212 mod_alloclightmap_state_t r_shadow_shadowmapatlas_state;
213 int r_shadow_shadowmapatlas_modelshadows_x;
214 int r_shadow_shadowmapatlas_modelshadows_y;
215 int r_shadow_shadowmapatlas_modelshadows_size;
216 int maxshadowtriangles;
219 int maxshadowvertices;
220 float *shadowvertex3f;
230 unsigned char *shadowsides;
231 int *shadowsideslist;
238 int r_shadow_buffer_numleafpvsbytes;
239 unsigned char *r_shadow_buffer_visitingleafpvs;
240 unsigned char *r_shadow_buffer_leafpvs;
241 int *r_shadow_buffer_leaflist;
243 int r_shadow_buffer_numsurfacepvsbytes;
244 unsigned char *r_shadow_buffer_surfacepvs;
245 int *r_shadow_buffer_surfacelist;
246 unsigned char *r_shadow_buffer_surfacesides;
248 int r_shadow_buffer_numshadowtrispvsbytes;
249 unsigned char *r_shadow_buffer_shadowtrispvs;
250 int r_shadow_buffer_numlighttrispvsbytes;
251 unsigned char *r_shadow_buffer_lighttrispvs;
253 rtexturepool_t *r_shadow_texturepool;
254 rtexture_t *r_shadow_attenuationgradienttexture;
255 rtexture_t *r_shadow_attenuation2dtexture;
256 rtexture_t *r_shadow_attenuation3dtexture;
257 skinframe_t *r_shadow_lightcorona;
258 rtexture_t *r_shadow_shadowmap2ddepthbuffer;
259 rtexture_t *r_shadow_shadowmap2ddepthtexture;
260 rtexture_t *r_shadow_shadowmapvsdcttexture;
262 GLuint r_shadow_prepassgeometryfbo;
263 GLuint r_shadow_prepasslightingdiffusespecularfbo;
264 GLuint r_shadow_prepasslightingdiffusefbo;
265 int r_shadow_prepass_width;
266 int r_shadow_prepass_height;
267 rtexture_t *r_shadow_prepassgeometrydepthbuffer;
268 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
269 rtexture_t *r_shadow_prepasslightingdiffusetexture;
270 rtexture_t *r_shadow_prepasslightingspeculartexture;
272 // keep track of the provided framebuffer info
273 static int r_shadow_fb_fbo;
274 static rtexture_t *r_shadow_fb_depthtexture;
275 static rtexture_t *r_shadow_fb_colortexture;
277 // lights are reloaded when this changes
278 char r_shadow_mapname[MAX_QPATH];
280 // buffer for doing corona fading
281 unsigned int r_shadow_occlusion_buf = 0;
283 // used only for light filters (cubemaps)
284 rtexturepool_t *r_shadow_filters_texturepool;
286 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
287 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
288 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
289 cvar_t r_shadow_deferred = {CVAR_SAVE, "r_shadow_deferred", "0", "uses image-based lighting instead of geometry-based lighting, the method used renders a depth image and a normalmap image, renders lights into separate diffuse and specular images, and then combines this into the normal rendering, requires r_shadow_shadowmapping"};
290 cvar_t r_shadow_usebihculling = {0, "r_shadow_usebihculling", "1", "use BIH (Bounding Interval Hierarchy) for culling lit surfaces instead of BSP (Binary Space Partitioning)"};
291 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
292 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
293 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
294 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
295 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
296 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
297 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
298 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
299 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
300 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
301 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
302 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
303 cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
304 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
305 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
306 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
307 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
308 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
309 cvar_t r_shadow_realtime_world_importlightentitiesfrommap = {0, "r_shadow_realtime_world_importlightentitiesfrommap", "1", "load lights from .ent file or map entities at startup if no .rtlights or .lights file is present (if set to 2, always use the .ent or map entities)"};
310 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
311 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
312 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
313 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
314 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation (slower than compileportalculling but more exact)"};
315 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
316 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
317 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "1", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes"};
318 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
319 cvar_t r_shadow_shadowmapping_useshadowsampler = {CVAR_SAVE, "r_shadow_shadowmapping_useshadowsampler", "1", "whether to use sampler2DShadow if available"};
320 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
321 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
322 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "limit of shadowmap side size - must be at least r_shadow_shadowmapping_bordersize+2"};
323 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "limit of shadowmap side size - can not be more than 1/8th of atlassize because lights store 6 sides (2x3 grid) and sometimes 12 sides (4x3 grid for shadows from EF_NOSELFSHADOW entities) and there are multiple lights..."};
324 cvar_t r_shadow_shadowmapping_texturesize = { CVAR_SAVE, "r_shadow_shadowmapping_texturesize", "8192", "size of shadowmap atlas texture - all shadowmaps are packed into this texture at frame start"};
325 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
326 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
327 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
328 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "5", "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_culllights_pvs = {CVAR_SAVE, "r_shadow_culllights_pvs", "1", "check if light overlaps any visible bsp leafs when determining if the light is visible"};
338 cvar_t r_shadow_culllights_trace = {CVAR_SAVE, "r_shadow_culllights_trace", "1", "use raytraces from the eye to random places within light bounds to determine if the light is visible"};
339 cvar_t r_shadow_culllights_trace_eyejitter = {CVAR_SAVE, "r_shadow_culllights_trace_eyejitter", "16", "offset eye location randomly by this much"};
340 cvar_t r_shadow_culllights_trace_enlarge = {CVAR_SAVE, "r_shadow_culllights_trace_enlarge", "0.1", "make light bounds bigger by *1.0+enlarge"};
341 cvar_t r_shadow_culllights_trace_samples = {CVAR_SAVE, "r_shadow_culllights_trace_samples", "16", "use this many traces to random positions (in addition to center trace)"};
342 cvar_t r_shadow_culllights_trace_tempsamples = {CVAR_SAVE, "r_shadow_culllights_trace_tempsamples", "16", "use this many traces if the light was created by csqc (no inter-frame caching), -1 disables the check (to avoid flicker entirely)"};
343 cvar_t r_shadow_culllights_trace_delay = {CVAR_SAVE, "r_shadow_culllights_trace_delay", "1", "light will be considered visible for this many seconds after any trace connects"};
344 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)"};
345 cvar_t r_shadow_bouncegrid_blur = {CVAR_SAVE, "r_shadow_bouncegrid_blur", "0", "apply a 1-radius blur on bouncegrid to denoise it and deal with boundary issues with surfaces"};
346 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"};
347 cvar_t r_shadow_bouncegrid_dynamic_bounceminimumintensity = { CVAR_SAVE, "r_shadow_bouncegrid_dynamic_bounceminimumintensity", "0.05", "stop bouncing once intensity drops below this fraction of the original particle color" };
348 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)"};
349 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"};
350 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"};
351 cvar_t r_shadow_bouncegrid_dynamic_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
352 cvar_t r_shadow_bouncegrid_dynamic_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_lightradiusscale", "2", "particles stop at this fraction of light radius (can be more than 1)"};
353 cvar_t r_shadow_bouncegrid_dynamic_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_maxbounce", "2", "maximum number of bounces for a particle (minimum is 0)"};
354 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"};
355 cvar_t r_shadow_bouncegrid_dynamic_quality = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_quality", "1", "amount of photons that should be fired (this is multiplied by spacing^2 to make it adaptive with spacing changes)"};
356 cvar_t r_shadow_bouncegrid_dynamic_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_spacing", "64", "unit size of bouncegrid pixel"};
357 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"};
358 cvar_t r_shadow_bouncegrid_dynamic_x = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_x", "64", "maximum texture size of bouncegrid on X axis"};
359 cvar_t r_shadow_bouncegrid_dynamic_y = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_y", "64", "maximum texture size of bouncegrid on Y axis"};
360 cvar_t r_shadow_bouncegrid_dynamic_z = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_z", "32", "maximum texture size of bouncegrid on Z axis"};
361 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"};
362 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)"};
363 cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
364 cvar_t r_shadow_bouncegrid_lightpathsize_conespread = {CVAR_SAVE, "r_shadow_bouncegrid_lightpathsize_conespread", "0.015625", "increase lightpathsize over distance at this rate per grid cell"};
365 cvar_t r_shadow_bouncegrid_lightpathsize_initial = {CVAR_SAVE, "r_shadow_bouncegrid_lightpathsize_initial", "0.5", "width (in grid cells) of the light path for accumulation of light in the bouncegrid texture"};
366 cvar_t r_shadow_bouncegrid_normalizevectors = { CVAR_SAVE, "r_shadow_bouncegrid_normalizevectors", "1", "normalize random vectors (otherwise their length can vary, which dims the lighting further from the light)" };
367 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"};
368 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "0.25", "brightness of particles contributing to bouncegrid texture"};
369 cvar_t r_shadow_bouncegrid_rng_seed = { CVAR_SAVE, "r_shadow_bouncegrid_rng_seed", "0", "0+ = use this number as RNG seed, -1 = use time instead for disco-like craziness in dynamic mode" };
370 cvar_t r_shadow_bouncegrid_rng_type = { CVAR_SAVE, "r_shadow_bouncegrid_rng_type", "0", "0 = Lehmer 128bit RNG (slow but high quality), 1 = lhcheeserand 32bit RNG (quick)" };
371 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"};
372 cvar_t r_shadow_bouncegrid_static = {CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
373 cvar_t r_shadow_bouncegrid_static_bounceminimumintensity = { CVAR_SAVE, "r_shadow_bouncegrid_static_bounceminimumintensity", "0.01", "stop bouncing once intensity drops below this fraction of the original particle color" };
374 cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
375 cvar_t r_shadow_bouncegrid_static_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_static_lightradiusscale", "2", "particles stop at this fraction of light radius (can be more than 1) when in static mode"};
376 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"};
377 cvar_t r_shadow_bouncegrid_static_maxphotons = {CVAR_SAVE, "r_shadow_bouncegrid_static_maxphotons", "250000", "upper bound on photons in static mode"};
378 cvar_t r_shadow_bouncegrid_static_quality = { CVAR_SAVE, "r_shadow_bouncegrid_static_quality", "16", "amount of photons that should be fired (this is multiplied by spacing^2 to make it adaptive with spacing changes)" };
379 cvar_t r_shadow_bouncegrid_static_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_static_spacing", "64", "unit size of bouncegrid pixel when in static mode"};
380 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
381 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"};
382 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!"};
383 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
384 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
385 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
386 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
387 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
388 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
389 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
390 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
391 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
392 cvar_t r_editlights_drawproperties = {0, "r_editlights_drawproperties", "1", "draw properties of currently selected light"};
393 cvar_t r_editlights_current_origin = {0, "r_editlights_current_origin", "0 0 0", "origin of selected light"};
394 cvar_t r_editlights_current_angles = {0, "r_editlights_current_angles", "0 0 0", "angles of selected light"};
395 cvar_t r_editlights_current_color = {0, "r_editlights_current_color", "1 1 1", "color of selected light"};
396 cvar_t r_editlights_current_radius = {0, "r_editlights_current_radius", "0", "radius of selected light"};
397 cvar_t r_editlights_current_corona = {0, "r_editlights_current_corona", "0", "corona intensity of selected light"};
398 cvar_t r_editlights_current_coronasize = {0, "r_editlights_current_coronasize", "0", "corona size of selected light"};
399 cvar_t r_editlights_current_style = {0, "r_editlights_current_style", "0", "style of selected light"};
400 cvar_t r_editlights_current_shadows = {0, "r_editlights_current_shadows", "0", "shadows flag of selected light"};
401 cvar_t r_editlights_current_cubemap = {0, "r_editlights_current_cubemap", "0", "cubemap of selected light"};
402 cvar_t r_editlights_current_ambient = {0, "r_editlights_current_ambient", "0", "ambient intensity of selected light"};
403 cvar_t r_editlights_current_diffuse = {0, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"};
404 cvar_t r_editlights_current_specular = {0, "r_editlights_current_specular", "1", "specular intensity of selected light"};
405 cvar_t r_editlights_current_normalmode = {0, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"};
406 cvar_t r_editlights_current_realtimemode = {0, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"};
408 r_shadow_bouncegrid_state_t r_shadow_bouncegrid_state;
410 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
411 #define ATTENTABLESIZE 256
412 // 1D gradient, 2D circle and 3D sphere attenuation textures
413 #define ATTEN1DSIZE 32
414 #define ATTEN2DSIZE 64
415 #define ATTEN3DSIZE 32
417 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
418 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
419 static float r_shadow_attentable[ATTENTABLESIZE+1];
421 rtlight_t *r_shadow_compilingrtlight;
422 static memexpandablearray_t r_shadow_worldlightsarray;
423 dlight_t *r_shadow_selectedlight;
424 dlight_t r_shadow_bufferlight;
425 vec3_t r_editlights_cursorlocation;
426 qboolean r_editlights_lockcursor;
428 extern int con_vislines;
430 void R_Shadow_UncompileWorldLights(void);
431 void R_Shadow_ClearWorldLights(void);
432 void R_Shadow_SaveWorldLights(void);
433 void R_Shadow_LoadWorldLights(void);
434 void R_Shadow_LoadLightsFile(void);
435 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
436 void R_Shadow_EditLights_Reload_f(void);
437 void R_Shadow_ValidateCvars(void);
438 static void R_Shadow_MakeTextures(void);
440 #define EDLIGHTSPRSIZE 8
441 skinframe_t *r_editlights_sprcursor;
442 skinframe_t *r_editlights_sprlight;
443 skinframe_t *r_editlights_sprnoshadowlight;
444 skinframe_t *r_editlights_sprcubemaplight;
445 skinframe_t *r_editlights_sprcubemapnoshadowlight;
446 skinframe_t *r_editlights_sprselection;
448 static void R_Shadow_DrawModelShadowMaps(void);
449 static void R_Shadow_MakeShadowMap(int texturesize);
450 static void R_Shadow_MakeVSDCT(void);
451 static void R_Shadow_SetShadowMode(void)
453 r_shadow_shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
454 r_shadow_shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
455 r_shadow_shadowmapmaxsize = bound(r_shadow_shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, r_shadow_shadowmaptexturesize / 8);
456 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
457 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
458 r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
459 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
460 r_shadow_shadowmapsampler = false;
461 r_shadow_shadowmappcf = 0;
462 r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
463 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
464 Mod_AllocLightmap_Init(&r_shadow_shadowmapatlas_state, r_main_mempool, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize);
465 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
467 switch(vid.renderpath)
469 case RENDERPATH_GL20:
470 if(r_shadow_shadowmapfilterquality < 0)
472 if (!r_fb.usedepthtextures)
473 r_shadow_shadowmappcf = 1;
474 else if((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && vid.support.arb_shadow && r_shadow_shadowmapshadowsampler)
476 r_shadow_shadowmapsampler = true;
477 r_shadow_shadowmappcf = 1;
479 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
480 r_shadow_shadowmappcf = 1;
481 else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa"))
482 r_shadow_shadowmappcf = 1;
484 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
488 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
489 switch (r_shadow_shadowmapfilterquality)
494 r_shadow_shadowmappcf = 1;
497 r_shadow_shadowmappcf = 1;
500 r_shadow_shadowmappcf = 2;
504 if (!r_fb.usedepthtextures)
505 r_shadow_shadowmapsampler = false;
506 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
508 case RENDERPATH_D3D9:
509 case RENDERPATH_D3D10:
510 case RENDERPATH_D3D11:
511 case RENDERPATH_SOFT:
512 r_shadow_shadowmapsampler = false;
513 r_shadow_shadowmappcf = 1;
514 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
516 case RENDERPATH_GL11:
517 case RENDERPATH_GL13:
518 case RENDERPATH_GLES1:
519 case RENDERPATH_GLES2:
524 if(R_CompileShader_CheckStaticParms())
528 qboolean R_Shadow_ShadowMappingEnabled(void)
530 switch (r_shadow_shadowmode)
532 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
539 static void R_Shadow_FreeShadowMaps(void)
541 Mod_AllocLightmap_Free(&r_shadow_shadowmapatlas_state);
543 R_Shadow_SetShadowMode();
545 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
549 if (r_shadow_shadowmap2ddepthtexture)
550 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
551 r_shadow_shadowmap2ddepthtexture = NULL;
553 if (r_shadow_shadowmap2ddepthbuffer)
554 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
555 r_shadow_shadowmap2ddepthbuffer = NULL;
557 if (r_shadow_shadowmapvsdcttexture)
558 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
559 r_shadow_shadowmapvsdcttexture = NULL;
562 static void r_shadow_start(void)
564 // allocate vertex processing arrays
565 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
566 r_shadow_attenuationgradienttexture = NULL;
567 r_shadow_attenuation2dtexture = NULL;
568 r_shadow_attenuation3dtexture = NULL;
569 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
570 r_shadow_shadowmap2ddepthtexture = NULL;
571 r_shadow_shadowmap2ddepthbuffer = NULL;
572 r_shadow_shadowmapvsdcttexture = NULL;
573 r_shadow_shadowmapmaxsize = 0;
574 r_shadow_shadowmaptexturesize = 0;
575 r_shadow_shadowmapfilterquality = -1;
576 r_shadow_shadowmapdepthbits = 0;
577 r_shadow_shadowmapvsdct = false;
578 r_shadow_shadowmapsampler = false;
579 r_shadow_shadowmappcf = 0;
582 R_Shadow_FreeShadowMaps();
584 r_shadow_texturepool = NULL;
585 r_shadow_filters_texturepool = NULL;
586 R_Shadow_ValidateCvars();
587 R_Shadow_MakeTextures();
588 r_shadow_scenemaxlights = 0;
589 r_shadow_scenenumlights = 0;
590 r_shadow_scenelightlist = NULL;
591 maxshadowtriangles = 0;
592 shadowelements = NULL;
593 maxshadowvertices = 0;
594 shadowvertex3f = NULL;
602 shadowmarklist = NULL;
607 shadowsideslist = NULL;
608 r_shadow_buffer_numleafpvsbytes = 0;
609 r_shadow_buffer_visitingleafpvs = NULL;
610 r_shadow_buffer_leafpvs = NULL;
611 r_shadow_buffer_leaflist = NULL;
612 r_shadow_buffer_numsurfacepvsbytes = 0;
613 r_shadow_buffer_surfacepvs = NULL;
614 r_shadow_buffer_surfacelist = NULL;
615 r_shadow_buffer_surfacesides = NULL;
616 r_shadow_buffer_numshadowtrispvsbytes = 0;
617 r_shadow_buffer_shadowtrispvs = NULL;
618 r_shadow_buffer_numlighttrispvsbytes = 0;
619 r_shadow_buffer_lighttrispvs = NULL;
621 r_shadow_usingdeferredprepass = false;
622 r_shadow_prepass_width = r_shadow_prepass_height = 0;
624 // determine renderpath specific capabilities, we don't need to figure
625 // these out per frame...
626 switch(vid.renderpath)
628 case RENDERPATH_GL20:
629 r_shadow_bouncegrid_state.allowdirectionalshading = true;
630 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
632 case RENDERPATH_GLES2:
633 // for performance reasons, do not use directional shading on GLES devices
634 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
636 // these renderpaths do not currently have the code to display the bouncegrid, so disable it on them...
637 case RENDERPATH_GL11:
638 case RENDERPATH_GL13:
639 case RENDERPATH_GLES1:
640 case RENDERPATH_SOFT:
641 case RENDERPATH_D3D9:
642 case RENDERPATH_D3D10:
643 case RENDERPATH_D3D11:
648 static void R_Shadow_FreeDeferred(void);
649 static void r_shadow_shutdown(void)
652 R_Shadow_UncompileWorldLights();
654 R_Shadow_FreeShadowMaps();
656 r_shadow_usingdeferredprepass = false;
657 if (r_shadow_prepass_width)
658 R_Shadow_FreeDeferred();
659 r_shadow_prepass_width = r_shadow_prepass_height = 0;
662 r_shadow_scenemaxlights = 0;
663 r_shadow_scenenumlights = 0;
664 if (r_shadow_scenelightlist)
665 Mem_Free(r_shadow_scenelightlist);
666 r_shadow_scenelightlist = NULL;
667 r_shadow_bouncegrid_state.highpixels = NULL;
668 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
669 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
670 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
671 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
672 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
673 r_shadow_bouncegrid_state.maxsplatpaths = 0;
674 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
675 r_shadow_attenuationgradienttexture = NULL;
676 r_shadow_attenuation2dtexture = NULL;
677 r_shadow_attenuation3dtexture = NULL;
678 R_FreeTexturePool(&r_shadow_texturepool);
679 R_FreeTexturePool(&r_shadow_filters_texturepool);
680 maxshadowtriangles = 0;
682 Mem_Free(shadowelements);
683 shadowelements = NULL;
685 Mem_Free(shadowvertex3f);
686 shadowvertex3f = NULL;
689 Mem_Free(vertexupdate);
692 Mem_Free(vertexremap);
698 Mem_Free(shadowmark);
701 Mem_Free(shadowmarklist);
702 shadowmarklist = NULL;
707 Mem_Free(shadowsides);
710 Mem_Free(shadowsideslist);
711 shadowsideslist = NULL;
712 r_shadow_buffer_numleafpvsbytes = 0;
713 if (r_shadow_buffer_visitingleafpvs)
714 Mem_Free(r_shadow_buffer_visitingleafpvs);
715 r_shadow_buffer_visitingleafpvs = NULL;
716 if (r_shadow_buffer_leafpvs)
717 Mem_Free(r_shadow_buffer_leafpvs);
718 r_shadow_buffer_leafpvs = NULL;
719 if (r_shadow_buffer_leaflist)
720 Mem_Free(r_shadow_buffer_leaflist);
721 r_shadow_buffer_leaflist = NULL;
722 r_shadow_buffer_numsurfacepvsbytes = 0;
723 if (r_shadow_buffer_surfacepvs)
724 Mem_Free(r_shadow_buffer_surfacepvs);
725 r_shadow_buffer_surfacepvs = NULL;
726 if (r_shadow_buffer_surfacelist)
727 Mem_Free(r_shadow_buffer_surfacelist);
728 r_shadow_buffer_surfacelist = NULL;
729 if (r_shadow_buffer_surfacesides)
730 Mem_Free(r_shadow_buffer_surfacesides);
731 r_shadow_buffer_surfacesides = NULL;
732 r_shadow_buffer_numshadowtrispvsbytes = 0;
733 if (r_shadow_buffer_shadowtrispvs)
734 Mem_Free(r_shadow_buffer_shadowtrispvs);
735 r_shadow_buffer_numlighttrispvsbytes = 0;
736 if (r_shadow_buffer_lighttrispvs)
737 Mem_Free(r_shadow_buffer_lighttrispvs);
740 static void r_shadow_newmap(void)
742 r_shadow_bouncegrid_state.highpixels = NULL;
743 if (r_shadow_bouncegrid_state.blurpixels[0]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL; }
744 if (r_shadow_bouncegrid_state.blurpixels[1]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL; }
745 if (r_shadow_bouncegrid_state.u8pixels) { Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL; }
746 if (r_shadow_bouncegrid_state.fp16pixels) { Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL; }
747 if (r_shadow_bouncegrid_state.splatpaths) { Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL; }
749 r_shadow_bouncegrid_state.maxsplatpaths = 0;
751 if (r_shadow_bouncegrid_state.texture) { R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL; }
752 if (r_shadow_lightcorona) { R_SkinFrame_MarkUsed(r_shadow_lightcorona); }
753 if (r_editlights_sprcursor) { R_SkinFrame_MarkUsed(r_editlights_sprcursor); }
754 if (r_editlights_sprlight) { R_SkinFrame_MarkUsed(r_editlights_sprlight); }
755 if (r_editlights_sprnoshadowlight) { R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight); }
756 if (r_editlights_sprcubemaplight) { R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight); }
757 if (r_editlights_sprcubemapnoshadowlight) { R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight); }
758 if (r_editlights_sprselection) { R_SkinFrame_MarkUsed(r_editlights_sprselection); }
759 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
760 R_Shadow_EditLights_Reload_f();
763 void R_Shadow_Init(void)
765 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
766 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
767 Cvar_RegisterVariable(&r_shadow_usebihculling);
768 Cvar_RegisterVariable(&r_shadow_usenormalmap);
769 Cvar_RegisterVariable(&r_shadow_debuglight);
770 Cvar_RegisterVariable(&r_shadow_deferred);
771 Cvar_RegisterVariable(&r_shadow_gloss);
772 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
773 Cvar_RegisterVariable(&r_shadow_glossintensity);
774 Cvar_RegisterVariable(&r_shadow_glossexponent);
775 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
776 Cvar_RegisterVariable(&r_shadow_glossexact);
777 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
778 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
779 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
780 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
781 Cvar_RegisterVariable(&r_shadow_projectdistance);
782 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
783 Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
784 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
785 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
786 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
787 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
788 Cvar_RegisterVariable(&r_shadow_realtime_world);
789 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
790 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
791 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
792 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
793 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
794 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
795 Cvar_RegisterVariable(&r_shadow_scissor);
796 Cvar_RegisterVariable(&r_shadow_shadowmapping);
797 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
798 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
799 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
800 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
801 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
802 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
803 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
804 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturesize);
805 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
806 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
807 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
808 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
809 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
810 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
811 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
812 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
813 Cvar_RegisterVariable(&r_shadow_polygonfactor);
814 Cvar_RegisterVariable(&r_shadow_polygonoffset);
815 Cvar_RegisterVariable(&r_shadow_texture3d);
816 Cvar_RegisterVariable(&r_shadow_culllights_pvs);
817 Cvar_RegisterVariable(&r_shadow_culllights_trace);
818 Cvar_RegisterVariable(&r_shadow_culllights_trace_eyejitter);
819 Cvar_RegisterVariable(&r_shadow_culllights_trace_enlarge);
820 Cvar_RegisterVariable(&r_shadow_culllights_trace_samples);
821 Cvar_RegisterVariable(&r_shadow_culllights_trace_tempsamples);
822 Cvar_RegisterVariable(&r_shadow_culllights_trace_delay);
823 Cvar_RegisterVariable(&r_shadow_bouncegrid);
824 Cvar_RegisterVariable(&r_shadow_bouncegrid_blur);
825 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
826 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_bounceminimumintensity);
827 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_culllightpaths);
828 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_directionalshading);
829 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_dlightparticlemultiplier);
830 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_hitmodels);
831 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_lightradiusscale);
832 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxbounce);
833 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxphotons);
834 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_quality);
835 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_spacing);
836 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_updateinterval);
837 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_x);
838 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_y);
839 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_z);
840 Cvar_RegisterVariable(&r_shadow_bouncegrid_floatcolors);
841 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
842 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
843 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize_conespread);
844 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize_initial);
845 Cvar_RegisterVariable(&r_shadow_bouncegrid_normalizevectors);
846 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
847 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
848 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_seed);
849 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_type);
850 Cvar_RegisterVariable(&r_shadow_bouncegrid_sortlightpaths);
851 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
852 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_bounceminimumintensity);
853 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
854 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
855 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
856 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxphotons);
857 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_quality);
858 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_spacing);
859 Cvar_RegisterVariable(&r_coronas);
860 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
861 Cvar_RegisterVariable(&r_coronas_occlusionquery);
862 Cvar_RegisterVariable(&gl_flashblend);
863 Cvar_RegisterVariable(&gl_ext_separatestencil);
864 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
865 R_Shadow_EditLights_Init();
866 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
867 r_shadow_scenemaxlights = 0;
868 r_shadow_scenenumlights = 0;
869 r_shadow_scenelightlist = NULL;
870 maxshadowtriangles = 0;
871 shadowelements = NULL;
872 maxshadowvertices = 0;
873 shadowvertex3f = NULL;
881 shadowmarklist = NULL;
886 shadowsideslist = NULL;
887 r_shadow_buffer_numleafpvsbytes = 0;
888 r_shadow_buffer_visitingleafpvs = NULL;
889 r_shadow_buffer_leafpvs = NULL;
890 r_shadow_buffer_leaflist = NULL;
891 r_shadow_buffer_numsurfacepvsbytes = 0;
892 r_shadow_buffer_surfacepvs = NULL;
893 r_shadow_buffer_surfacelist = NULL;
894 r_shadow_buffer_surfacesides = NULL;
895 r_shadow_buffer_shadowtrispvs = NULL;
896 r_shadow_buffer_lighttrispvs = NULL;
897 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
900 matrix4x4_t matrix_attenuationxyz =
903 {0.5, 0.0, 0.0, 0.5},
904 {0.0, 0.5, 0.0, 0.5},
905 {0.0, 0.0, 0.5, 0.5},
910 matrix4x4_t matrix_attenuationz =
913 {0.0, 0.0, 0.5, 0.5},
914 {0.0, 0.0, 0.0, 0.5},
915 {0.0, 0.0, 0.0, 0.5},
920 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
922 numvertices = ((numvertices + 255) & ~255) * vertscale;
923 numtriangles = ((numtriangles + 255) & ~255) * triscale;
924 // make sure shadowelements is big enough for this volume
925 if (maxshadowtriangles < numtriangles)
927 maxshadowtriangles = numtriangles;
929 Mem_Free(shadowelements);
930 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
932 // make sure shadowvertex3f is big enough for this volume
933 if (maxshadowvertices < numvertices)
935 maxshadowvertices = numvertices;
937 Mem_Free(shadowvertex3f);
938 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
942 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
944 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
945 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
946 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
947 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
948 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
950 if (r_shadow_buffer_visitingleafpvs)
951 Mem_Free(r_shadow_buffer_visitingleafpvs);
952 if (r_shadow_buffer_leafpvs)
953 Mem_Free(r_shadow_buffer_leafpvs);
954 if (r_shadow_buffer_leaflist)
955 Mem_Free(r_shadow_buffer_leaflist);
956 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
957 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
958 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
959 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
961 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
963 if (r_shadow_buffer_surfacepvs)
964 Mem_Free(r_shadow_buffer_surfacepvs);
965 if (r_shadow_buffer_surfacelist)
966 Mem_Free(r_shadow_buffer_surfacelist);
967 if (r_shadow_buffer_surfacesides)
968 Mem_Free(r_shadow_buffer_surfacesides);
969 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
970 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
971 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
972 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
974 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
976 if (r_shadow_buffer_shadowtrispvs)
977 Mem_Free(r_shadow_buffer_shadowtrispvs);
978 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
979 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
981 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
983 if (r_shadow_buffer_lighttrispvs)
984 Mem_Free(r_shadow_buffer_lighttrispvs);
985 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
986 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
990 void R_Shadow_PrepareShadowMark(int numtris)
992 // make sure shadowmark is big enough for this volume
993 if (maxshadowmark < numtris)
995 maxshadowmark = numtris;
997 Mem_Free(shadowmark);
999 Mem_Free(shadowmarklist);
1000 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
1001 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
1002 shadowmarkcount = 0;
1005 // if shadowmarkcount wrapped we clear the array and adjust accordingly
1006 if (shadowmarkcount == 0)
1008 shadowmarkcount = 1;
1009 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
1014 void R_Shadow_PrepareShadowSides(int numtris)
1016 if (maxshadowsides < numtris)
1018 maxshadowsides = numtris;
1020 Mem_Free(shadowsides);
1021 if (shadowsideslist)
1022 Mem_Free(shadowsideslist);
1023 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
1024 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
1029 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)
1032 int outtriangles = 0, outvertices = 0;
1034 const float *vertex;
1035 float ratio, direction[3], projectvector[3];
1037 if (projectdirection)
1038 VectorScale(projectdirection, projectdistance, projectvector);
1040 VectorClear(projectvector);
1042 // create the vertices
1043 if (projectdirection)
1045 for (i = 0;i < numshadowmarktris;i++)
1047 element = inelement3i + shadowmarktris[i] * 3;
1048 for (j = 0;j < 3;j++)
1050 if (vertexupdate[element[j]] != vertexupdatenum)
1052 vertexupdate[element[j]] = vertexupdatenum;
1053 vertexremap[element[j]] = outvertices;
1054 vertex = invertex3f + element[j] * 3;
1055 // project one copy of the vertex according to projectvector
1056 VectorCopy(vertex, outvertex3f);
1057 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1066 for (i = 0;i < numshadowmarktris;i++)
1068 element = inelement3i + shadowmarktris[i] * 3;
1069 for (j = 0;j < 3;j++)
1071 if (vertexupdate[element[j]] != vertexupdatenum)
1073 vertexupdate[element[j]] = vertexupdatenum;
1074 vertexremap[element[j]] = outvertices;
1075 vertex = invertex3f + element[j] * 3;
1076 // project one copy of the vertex to the sphere radius of the light
1077 // (FIXME: would projecting it to the light box be better?)
1078 VectorSubtract(vertex, projectorigin, direction);
1079 ratio = projectdistance / VectorLength(direction);
1080 VectorCopy(vertex, outvertex3f);
1081 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1089 if (r_shadow_frontsidecasting.integer)
1091 for (i = 0;i < numshadowmarktris;i++)
1093 int remappedelement[3];
1095 const int *neighbortriangle;
1097 markindex = shadowmarktris[i] * 3;
1098 element = inelement3i + markindex;
1099 neighbortriangle = inneighbor3i + markindex;
1100 // output the front and back triangles
1101 outelement3i[0] = vertexremap[element[0]];
1102 outelement3i[1] = vertexremap[element[1]];
1103 outelement3i[2] = vertexremap[element[2]];
1104 outelement3i[3] = vertexremap[element[2]] + 1;
1105 outelement3i[4] = vertexremap[element[1]] + 1;
1106 outelement3i[5] = vertexremap[element[0]] + 1;
1110 // output the sides (facing outward from this triangle)
1111 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1113 remappedelement[0] = vertexremap[element[0]];
1114 remappedelement[1] = vertexremap[element[1]];
1115 outelement3i[0] = remappedelement[1];
1116 outelement3i[1] = remappedelement[0];
1117 outelement3i[2] = remappedelement[0] + 1;
1118 outelement3i[3] = remappedelement[1];
1119 outelement3i[4] = remappedelement[0] + 1;
1120 outelement3i[5] = remappedelement[1] + 1;
1125 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1127 remappedelement[1] = vertexremap[element[1]];
1128 remappedelement[2] = vertexremap[element[2]];
1129 outelement3i[0] = remappedelement[2];
1130 outelement3i[1] = remappedelement[1];
1131 outelement3i[2] = remappedelement[1] + 1;
1132 outelement3i[3] = remappedelement[2];
1133 outelement3i[4] = remappedelement[1] + 1;
1134 outelement3i[5] = remappedelement[2] + 1;
1139 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1141 remappedelement[0] = vertexremap[element[0]];
1142 remappedelement[2] = vertexremap[element[2]];
1143 outelement3i[0] = remappedelement[0];
1144 outelement3i[1] = remappedelement[2];
1145 outelement3i[2] = remappedelement[2] + 1;
1146 outelement3i[3] = remappedelement[0];
1147 outelement3i[4] = remappedelement[2] + 1;
1148 outelement3i[5] = remappedelement[0] + 1;
1157 for (i = 0;i < numshadowmarktris;i++)
1159 int remappedelement[3];
1161 const int *neighbortriangle;
1163 markindex = shadowmarktris[i] * 3;
1164 element = inelement3i + markindex;
1165 neighbortriangle = inneighbor3i + markindex;
1166 // output the front and back triangles
1167 outelement3i[0] = vertexremap[element[2]];
1168 outelement3i[1] = vertexremap[element[1]];
1169 outelement3i[2] = vertexremap[element[0]];
1170 outelement3i[3] = vertexremap[element[0]] + 1;
1171 outelement3i[4] = vertexremap[element[1]] + 1;
1172 outelement3i[5] = vertexremap[element[2]] + 1;
1176 // output the sides (facing outward from this triangle)
1177 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1179 remappedelement[0] = vertexremap[element[0]];
1180 remappedelement[1] = vertexremap[element[1]];
1181 outelement3i[0] = remappedelement[0];
1182 outelement3i[1] = remappedelement[1];
1183 outelement3i[2] = remappedelement[1] + 1;
1184 outelement3i[3] = remappedelement[0];
1185 outelement3i[4] = remappedelement[1] + 1;
1186 outelement3i[5] = remappedelement[0] + 1;
1191 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1193 remappedelement[1] = vertexremap[element[1]];
1194 remappedelement[2] = vertexremap[element[2]];
1195 outelement3i[0] = remappedelement[1];
1196 outelement3i[1] = remappedelement[2];
1197 outelement3i[2] = remappedelement[2] + 1;
1198 outelement3i[3] = remappedelement[1];
1199 outelement3i[4] = remappedelement[2] + 1;
1200 outelement3i[5] = remappedelement[1] + 1;
1205 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1207 remappedelement[0] = vertexremap[element[0]];
1208 remappedelement[2] = vertexremap[element[2]];
1209 outelement3i[0] = remappedelement[2];
1210 outelement3i[1] = remappedelement[0];
1211 outelement3i[2] = remappedelement[0] + 1;
1212 outelement3i[3] = remappedelement[2];
1213 outelement3i[4] = remappedelement[0] + 1;
1214 outelement3i[5] = remappedelement[2] + 1;
1222 *outnumvertices = outvertices;
1223 return outtriangles;
1226 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)
1229 int outtriangles = 0, outvertices = 0;
1231 const float *vertex;
1232 float ratio, direction[3], projectvector[3];
1235 if (projectdirection)
1236 VectorScale(projectdirection, projectdistance, projectvector);
1238 VectorClear(projectvector);
1240 for (i = 0;i < numshadowmarktris;i++)
1242 int remappedelement[3];
1244 const int *neighbortriangle;
1246 markindex = shadowmarktris[i] * 3;
1247 neighbortriangle = inneighbor3i + markindex;
1248 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1249 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1250 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1251 if (side[0] + side[1] + side[2] == 0)
1255 element = inelement3i + markindex;
1257 // create the vertices
1258 for (j = 0;j < 3;j++)
1260 if (side[j] + side[j+1] == 0)
1263 if (vertexupdate[k] != vertexupdatenum)
1265 vertexupdate[k] = vertexupdatenum;
1266 vertexremap[k] = outvertices;
1267 vertex = invertex3f + k * 3;
1268 VectorCopy(vertex, outvertex3f);
1269 if (projectdirection)
1271 // project one copy of the vertex according to projectvector
1272 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1276 // project one copy of the vertex to the sphere radius of the light
1277 // (FIXME: would projecting it to the light box be better?)
1278 VectorSubtract(vertex, projectorigin, direction);
1279 ratio = projectdistance / VectorLength(direction);
1280 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1287 // output the sides (facing outward from this triangle)
1290 remappedelement[0] = vertexremap[element[0]];
1291 remappedelement[1] = vertexremap[element[1]];
1292 outelement3i[0] = remappedelement[1];
1293 outelement3i[1] = remappedelement[0];
1294 outelement3i[2] = remappedelement[0] + 1;
1295 outelement3i[3] = remappedelement[1];
1296 outelement3i[4] = remappedelement[0] + 1;
1297 outelement3i[5] = remappedelement[1] + 1;
1304 remappedelement[1] = vertexremap[element[1]];
1305 remappedelement[2] = vertexremap[element[2]];
1306 outelement3i[0] = remappedelement[2];
1307 outelement3i[1] = remappedelement[1];
1308 outelement3i[2] = remappedelement[1] + 1;
1309 outelement3i[3] = remappedelement[2];
1310 outelement3i[4] = remappedelement[1] + 1;
1311 outelement3i[5] = remappedelement[2] + 1;
1318 remappedelement[0] = vertexremap[element[0]];
1319 remappedelement[2] = vertexremap[element[2]];
1320 outelement3i[0] = remappedelement[0];
1321 outelement3i[1] = remappedelement[2];
1322 outelement3i[2] = remappedelement[2] + 1;
1323 outelement3i[3] = remappedelement[0];
1324 outelement3i[4] = remappedelement[2] + 1;
1325 outelement3i[5] = remappedelement[0] + 1;
1332 *outnumvertices = outvertices;
1333 return outtriangles;
1336 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)
1342 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1344 tend = firsttriangle + numtris;
1345 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1347 // surface box entirely inside light box, no box cull
1348 if (projectdirection)
1350 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1352 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1353 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1354 shadowmarklist[numshadowmark++] = t;
1359 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1360 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1361 shadowmarklist[numshadowmark++] = t;
1366 // surface box not entirely inside light box, cull each triangle
1367 if (projectdirection)
1369 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1371 v[0] = invertex3f + e[0] * 3;
1372 v[1] = invertex3f + e[1] * 3;
1373 v[2] = invertex3f + e[2] * 3;
1374 TriangleNormal(v[0], v[1], v[2], normal);
1375 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1376 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1377 shadowmarklist[numshadowmark++] = t;
1382 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1384 v[0] = invertex3f + e[0] * 3;
1385 v[1] = invertex3f + e[1] * 3;
1386 v[2] = invertex3f + e[2] * 3;
1387 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1388 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1389 shadowmarklist[numshadowmark++] = t;
1395 static qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1400 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1402 // check if the shadow volume intersects the near plane
1404 // a ray between the eye and light origin may intersect the caster,
1405 // indicating that the shadow may touch the eye location, however we must
1406 // test the near plane (a polygon), not merely the eye location, so it is
1407 // easiest to enlarge the caster bounding shape slightly for this.
1413 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)
1415 int i, tris, outverts;
1416 if (projectdistance < 0.1)
1418 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1421 if (!numverts || !nummarktris)
1423 // make sure shadowelements is big enough for this volume
1424 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1425 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1427 if (maxvertexupdate < numverts)
1429 maxvertexupdate = numverts;
1431 Mem_Free(vertexupdate);
1433 Mem_Free(vertexremap);
1434 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1435 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1436 vertexupdatenum = 0;
1439 if (vertexupdatenum == 0)
1441 vertexupdatenum = 1;
1442 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1443 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1446 for (i = 0;i < nummarktris;i++)
1447 shadowmark[marktris[i]] = shadowmarkcount;
1449 if (r_shadow_compilingrtlight)
1451 // if we're compiling an rtlight, capture the mesh
1452 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1453 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1454 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1455 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1457 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1459 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1460 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1461 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1465 // decide which type of shadow to generate and set stencil mode
1466 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1467 // generate the sides or a solid volume, depending on type
1468 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1469 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1471 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1472 r_refdef.stats[r_stat_lights_dynamicshadowtriangles] += tris;
1473 r_refdef.stats[r_stat_lights_shadowtriangles] += tris;
1474 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1476 // increment stencil if frontface is infront of depthbuffer
1477 GL_CullFace(r_refdef.view.cullface_front);
1478 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1479 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1480 // decrement stencil if backface is infront of depthbuffer
1481 GL_CullFace(r_refdef.view.cullface_back);
1482 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1484 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1486 // decrement stencil if backface is behind depthbuffer
1487 GL_CullFace(r_refdef.view.cullface_front);
1488 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1489 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1490 // increment stencil if frontface is behind depthbuffer
1491 GL_CullFace(r_refdef.view.cullface_back);
1492 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1494 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1495 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1499 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1501 // p1, p2, p3 are in the cubemap's local coordinate system
1502 // bias = border/(size - border)
1505 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1506 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1507 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1508 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1510 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1511 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1512 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1513 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1515 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1516 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1517 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1519 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1520 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1521 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1522 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1524 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1525 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1526 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1527 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1529 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1530 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1531 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1533 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1534 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1535 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1536 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1538 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1539 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1540 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1541 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1543 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1544 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1545 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1550 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1552 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1553 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1556 VectorSubtract(maxs, mins, radius);
1557 VectorScale(radius, 0.5f, radius);
1558 VectorAdd(mins, radius, center);
1559 Matrix4x4_Transform(worldtolight, center, lightcenter);
1560 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1561 VectorSubtract(lightcenter, lightradius, pmin);
1562 VectorAdd(lightcenter, lightradius, pmax);
1564 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1565 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1566 if(ap1 > bias*an1 && ap2 > bias*an2)
1568 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1569 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1570 if(an1 > bias*ap1 && an2 > bias*ap2)
1572 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1573 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1575 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1576 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1577 if(ap1 > bias*an1 && ap2 > bias*an2)
1579 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1580 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1581 if(an1 > bias*ap1 && an2 > bias*ap2)
1583 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1584 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1586 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1587 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1588 if(ap1 > bias*an1 && ap2 > bias*an2)
1590 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1591 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1592 if(an1 > bias*ap1 && an2 > bias*ap2)
1594 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1595 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1600 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1602 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1604 // p is in the cubemap's local coordinate system
1605 // bias = border/(size - border)
1606 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1607 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1608 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1610 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1611 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1612 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1613 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1614 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1615 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1619 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1623 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1624 float scale = (size - 2*border)/size, len;
1625 float bias = border / (float)(size - border), dp, dn, ap, an;
1626 // check if cone enclosing side would cross frustum plane
1627 scale = 2 / (scale*scale + 2);
1628 Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
1629 for (i = 0;i < 5;i++)
1631 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
1633 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1634 len = scale*VectorLength2(n);
1635 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1636 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1637 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1639 if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1641 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1642 len = scale*VectorLength2(n);
1643 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1644 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1645 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1647 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1648 // check if frustum corners/origin cross plane sides
1650 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1651 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1652 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1653 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1654 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1655 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1656 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1657 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1658 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1659 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1660 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1661 for (i = 0;i < 4;i++)
1663 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1664 VectorSubtract(n, p, n);
1665 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1666 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1667 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1668 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1669 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1670 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1671 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1672 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1673 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1676 // finite version, assumes corners are a finite distance from origin dependent on far plane
1677 for (i = 0;i < 5;i++)
1679 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1680 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1681 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1682 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1683 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1684 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1685 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1686 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1687 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1688 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1691 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1694 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)
1702 int mask, surfacemask = 0;
1703 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1705 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1706 tend = firsttriangle + numtris;
1707 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1709 // surface box entirely inside light box, no box cull
1710 if (projectdirection)
1712 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1714 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1715 TriangleNormal(v[0], v[1], v[2], normal);
1716 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1718 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1719 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1720 surfacemask |= mask;
1723 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;
1724 shadowsides[numshadowsides] = mask;
1725 shadowsideslist[numshadowsides++] = t;
1732 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1734 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1735 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1737 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1738 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1739 surfacemask |= mask;
1742 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;
1743 shadowsides[numshadowsides] = mask;
1744 shadowsideslist[numshadowsides++] = t;
1752 // surface box not entirely inside light box, cull each triangle
1753 if (projectdirection)
1755 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1757 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1758 TriangleNormal(v[0], v[1], v[2], normal);
1759 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1760 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1762 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1763 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1764 surfacemask |= mask;
1767 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1768 shadowsides[numshadowsides] = mask;
1769 shadowsideslist[numshadowsides++] = t;
1776 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1778 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1779 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1780 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1782 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1783 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1784 surfacemask |= mask;
1787 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;
1788 shadowsides[numshadowsides] = mask;
1789 shadowsideslist[numshadowsides++] = t;
1798 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)
1800 int i, j, outtriangles = 0;
1801 int *outelement3i[6];
1802 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1804 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1805 // make sure shadowelements is big enough for this mesh
1806 if (maxshadowtriangles < outtriangles)
1807 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1809 // compute the offset and size of the separate index lists for each cubemap side
1811 for (i = 0;i < 6;i++)
1813 outelement3i[i] = shadowelements + outtriangles * 3;
1814 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1815 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1816 outtriangles += sidetotals[i];
1819 // gather up the (sparse) triangles into separate index lists for each cubemap side
1820 for (i = 0;i < numsidetris;i++)
1822 const int *element = elements + sidetris[i] * 3;
1823 for (j = 0;j < 6;j++)
1825 if (sides[i] & (1 << j))
1827 outelement3i[j][0] = element[0];
1828 outelement3i[j][1] = element[1];
1829 outelement3i[j][2] = element[2];
1830 outelement3i[j] += 3;
1835 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1838 static void R_Shadow_MakeTextures_MakeCorona(void)
1842 unsigned char pixels[32][32][4];
1843 for (y = 0;y < 32;y++)
1845 dy = (y - 15.5f) * (1.0f / 16.0f);
1846 for (x = 0;x < 32;x++)
1848 dx = (x - 15.5f) * (1.0f / 16.0f);
1849 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1850 a = bound(0, a, 255);
1851 pixels[y][x][0] = a;
1852 pixels[y][x][1] = a;
1853 pixels[y][x][2] = a;
1854 pixels[y][x][3] = 255;
1857 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, false);
1860 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1862 float dist = sqrt(x*x+y*y+z*z);
1863 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1864 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1865 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1868 static void R_Shadow_MakeTextures(void)
1871 float intensity, dist;
1873 R_Shadow_FreeShadowMaps();
1874 R_FreeTexturePool(&r_shadow_texturepool);
1875 r_shadow_texturepool = R_AllocTexturePool();
1876 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1877 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1878 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1879 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1880 for (x = 0;x <= ATTENTABLESIZE;x++)
1882 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1883 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1884 r_shadow_attentable[x] = bound(0, intensity, 1);
1886 // 1D gradient texture
1887 for (x = 0;x < ATTEN1DSIZE;x++)
1888 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1889 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1890 // 2D circle texture
1891 for (y = 0;y < ATTEN2DSIZE;y++)
1892 for (x = 0;x < ATTEN2DSIZE;x++)
1893 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);
1894 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1895 // 3D sphere texture
1896 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1898 for (z = 0;z < ATTEN3DSIZE;z++)
1899 for (y = 0;y < ATTEN3DSIZE;y++)
1900 for (x = 0;x < ATTEN3DSIZE;x++)
1901 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));
1902 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);
1905 r_shadow_attenuation3dtexture = NULL;
1908 R_Shadow_MakeTextures_MakeCorona();
1910 // Editor light sprites
1911 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1928 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1929 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1946 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1947 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1964 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1965 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1982 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1983 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
2000 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
2001 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
2018 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
2021 void R_Shadow_ValidateCvars(void)
2023 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
2024 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
2025 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
2026 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
2027 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
2028 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
2031 void R_Shadow_RenderMode_Begin(void)
2037 R_Shadow_ValidateCvars();
2039 if (!r_shadow_attenuation2dtexture
2040 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
2041 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
2042 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
2043 R_Shadow_MakeTextures();
2046 R_Mesh_ResetTextureState();
2047 GL_BlendFunc(GL_ONE, GL_ZERO);
2048 GL_DepthRange(0, 1);
2049 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
2051 GL_DepthMask(false);
2052 GL_Color(0, 0, 0, 1);
2053 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2055 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2057 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
2059 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
2060 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
2062 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
2064 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
2065 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
2069 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
2070 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
2073 switch(vid.renderpath)
2075 case RENDERPATH_GL20:
2076 case RENDERPATH_D3D9:
2077 case RENDERPATH_D3D10:
2078 case RENDERPATH_D3D11:
2079 case RENDERPATH_SOFT:
2080 case RENDERPATH_GLES2:
2081 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
2083 case RENDERPATH_GL11:
2084 case RENDERPATH_GL13:
2085 case RENDERPATH_GLES1:
2086 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
2087 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
2088 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
2089 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
2090 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
2091 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
2093 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
2099 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
2100 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
2101 r_shadow_drawbuffer = drawbuffer;
2102 r_shadow_readbuffer = readbuffer;
2104 r_shadow_cullface_front = r_refdef.view.cullface_front;
2105 r_shadow_cullface_back = r_refdef.view.cullface_back;
2108 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
2110 rsurface.rtlight = rtlight;
2113 void R_Shadow_RenderMode_Reset(void)
2115 R_Mesh_ResetTextureState();
2116 R_Mesh_SetRenderTargets(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture, NULL, NULL, NULL);
2117 R_SetViewport(&r_refdef.view.viewport);
2118 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
2119 GL_DepthRange(0, 1);
2121 GL_DepthMask(false);
2122 GL_DepthFunc(GL_LEQUAL);
2123 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2124 r_refdef.view.cullface_front = r_shadow_cullface_front;
2125 r_refdef.view.cullface_back = r_shadow_cullface_back;
2126 GL_CullFace(r_refdef.view.cullface_back);
2127 GL_Color(1, 1, 1, 1);
2128 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2129 GL_BlendFunc(GL_ONE, GL_ZERO);
2130 R_SetupShader_Generic_NoTexture(false, false);
2131 r_shadow_usingshadowmap2d = false;
2132 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2135 void R_Shadow_ClearStencil(void)
2137 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2138 r_refdef.stats[r_stat_lights_clears]++;
2141 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2143 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2144 if (r_shadow_rendermode == mode)
2146 R_Shadow_RenderMode_Reset();
2147 GL_DepthFunc(GL_LESS);
2148 GL_ColorMask(0, 0, 0, 0);
2149 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2150 GL_CullFace(GL_NONE);
2151 R_SetupShader_DepthOrShadow(false, false, false); // FIXME test if we have a skeletal model?
2152 r_shadow_rendermode = mode;
2157 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2158 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2159 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2161 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2162 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2163 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2168 static void R_Shadow_MakeVSDCT(void)
2170 // maps to a 2x3 texture rectangle with normalized coordinates
2175 // stores abs(dir.xy), offset.xy/2.5
2176 unsigned char data[4*6] =
2178 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2179 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2180 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2181 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2182 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2183 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2185 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2188 static void R_Shadow_MakeShadowMap(int texturesize)
2190 switch (r_shadow_shadowmode)
2192 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2193 if (r_shadow_shadowmap2ddepthtexture) return;
2194 if (r_fb.usedepthtextures)
2196 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);
2197 r_shadow_shadowmap2ddepthbuffer = NULL;
2198 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2202 r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", texturesize, texturesize, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2203 r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
2204 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2212 void R_Shadow_ClearShadowMapTexture(void)
2214 r_viewport_t viewport;
2215 float clearcolor[4];
2217 // if they don't exist, create our textures now
2218 if (!r_shadow_shadowmap2ddepthtexture)
2219 R_Shadow_MakeShadowMap(r_shadow_shadowmaptexturesize);
2220 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2221 R_Shadow_MakeVSDCT();
2223 // we're setting up to render shadowmaps, so change rendermode
2224 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2226 R_Mesh_ResetTextureState();
2227 R_Shadow_RenderMode_Reset();
2228 if (r_shadow_shadowmap2ddepthbuffer)
2229 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2231 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2232 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2233 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2237 // we have to set a viewport to clear anything in some renderpaths (D3D)
2238 R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize, 0, 0, 1.0, 1.0, 0.001f, 1.0f, NULL);
2239 R_SetViewport(&viewport);
2240 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2241 if (r_shadow_shadowmap2ddepthbuffer)
2242 GL_ColorMask(1, 1, 1, 1);
2244 GL_ColorMask(0, 0, 0, 0);
2245 switch (vid.renderpath)
2247 case RENDERPATH_GL11:
2248 case RENDERPATH_GL13:
2249 case RENDERPATH_GL20:
2250 case RENDERPATH_SOFT:
2251 case RENDERPATH_GLES1:
2252 case RENDERPATH_GLES2:
2253 GL_CullFace(r_refdef.view.cullface_back);
2255 case RENDERPATH_D3D9:
2256 case RENDERPATH_D3D10:
2257 case RENDERPATH_D3D11:
2258 // we invert the cull mode because we flip the projection matrix
2259 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2260 GL_CullFace(r_refdef.view.cullface_front);
2263 Vector4Set(clearcolor, 1, 1, 1, 1);
2264 if (r_shadow_shadowmap2ddepthbuffer)
2265 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2267 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2270 static void R_Shadow_SetShadowmapParametersForLight(qboolean noselfshadowpass)
2272 int size = rsurface.rtlight->shadowmapatlassidesize;
2273 float nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2274 float farclip = 1.0f;
2275 float bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2276 r_shadow_lightshadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
2277 r_shadow_lightshadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
2278 r_shadow_lightshadowmap_texturescale[2] = rsurface.rtlight->shadowmapatlasposition[0] + (noselfshadowpass ? size * 2 : 0);
2279 r_shadow_lightshadowmap_texturescale[3] = rsurface.rtlight->shadowmapatlasposition[1];
2280 r_shadow_lightshadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2281 r_shadow_lightshadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2282 r_shadow_lightshadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2283 r_shadow_lightshadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2284 if (r_shadow_shadowmap2ddepthbuffer)
2286 // completely different meaning than in depthtexture approach
2287 r_shadow_lightshadowmap_parameters[1] = 0;
2288 r_shadow_lightshadowmap_parameters[3] = -bias;
2292 static void R_Shadow_RenderMode_ShadowMap(int side, int size, int x, int y)
2294 float nearclip, farclip, bias;
2295 r_viewport_t viewport;
2297 float clearcolor[4];
2299 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_SHADOWMAP2D)
2301 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2303 R_Mesh_ResetTextureState();
2304 R_Shadow_RenderMode_Reset();
2305 if (r_shadow_shadowmap2ddepthbuffer)
2306 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2308 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2309 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2310 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2315 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2317 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2319 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
2320 R_SetViewport(&viewport);
2321 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2322 flipped = (side & 1) ^ (side >> 2);
2323 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2324 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2326 Vector4Set(clearcolor, 1,1,1,1);
2327 if (r_shadow_shadowmap2ddepthbuffer)
2328 GL_ColorMask(1,1,1,1);
2330 GL_ColorMask(0,0,0,0);
2331 switch(vid.renderpath)
2333 case RENDERPATH_GL11:
2334 case RENDERPATH_GL13:
2335 case RENDERPATH_GL20:
2336 case RENDERPATH_SOFT:
2337 case RENDERPATH_GLES1:
2338 case RENDERPATH_GLES2:
2339 GL_CullFace(r_refdef.view.cullface_back);
2341 case RENDERPATH_D3D9:
2342 case RENDERPATH_D3D10:
2343 case RENDERPATH_D3D11:
2344 // we invert the cull mode because we flip the projection matrix
2345 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2346 GL_CullFace(r_refdef.view.cullface_front);
2350 // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
2351 r_shadow_shadowmapside = side;
2354 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass)
2356 R_Mesh_ResetTextureState();
2359 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2360 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2361 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2362 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2365 R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
2366 R_Shadow_RenderMode_Reset();
2367 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2369 GL_DepthFunc(GL_EQUAL);
2370 // do global setup needed for the chosen lighting mode
2371 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2372 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2373 r_shadow_usingshadowmap2d = shadowmapping;
2374 r_shadow_rendermode = r_shadow_lightingrendermode;
2375 // only draw light where this geometry was already rendered AND the
2376 // stencil is 128 (values other than this mean shadow)
2378 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2380 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2383 static const unsigned short bboxelements[36] =
2393 static const float bboxpoints[8][3] =
2405 void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping)
2408 float vertex3f[8*3];
2409 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2410 // do global setup needed for the chosen lighting mode
2411 R_Shadow_RenderMode_Reset();
2412 r_shadow_rendermode = r_shadow_lightingrendermode;
2413 R_EntityMatrix(&identitymatrix);
2414 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2415 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2416 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
2417 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2419 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
2421 r_shadow_usingshadowmap2d = shadowmapping;
2423 // render the lighting
2424 R_SetupShader_DeferredLight(rsurface.rtlight);
2425 for (i = 0;i < 8;i++)
2426 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2427 GL_ColorMask(1,1,1,1);
2428 GL_DepthMask(false);
2429 GL_DepthRange(0, 1);
2430 GL_PolygonOffset(0, 0);
2432 GL_DepthFunc(GL_GREATER);
2433 GL_CullFace(r_refdef.view.cullface_back);
2434 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
2435 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2438 #define MAXBOUNCEGRIDSPLATSIZE 7
2439 #define MAXBOUNCEGRIDSPLATSIZE1 (MAXBOUNCEGRIDSPLATSIZE+1)
2441 // these are temporary data per-frame, sorted and performed in a more
2442 // cache-friendly order than the original photons
2443 typedef struct r_shadow_bouncegrid_splatpath_s
2449 vec_t splatintensity;
2450 vec_t splatsize_current;
2451 vec_t splatsize_perstep;
2452 int remainingsplats;
2454 r_shadow_bouncegrid_splatpath_t;
2456 static void R_Shadow_BounceGrid_AddSplatPath(vec3_t originalstart, vec3_t originalend, vec3_t color, vec_t distancetraveled)
2466 r_shadow_bouncegrid_splatpath_t *path;
2468 // cull paths that fail R_CullBox in dynamic mode
2469 if (!r_shadow_bouncegrid_state.settings.staticmode
2470 && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
2472 vec3_t cullmins, cullmaxs;
2473 cullmins[0] = min(originalstart[0], originalend[0]) - r_shadow_bouncegrid_state.settings.spacing[0];
2474 cullmins[1] = min(originalstart[1], originalend[1]) - r_shadow_bouncegrid_state.settings.spacing[1];
2475 cullmins[2] = min(originalstart[2], originalend[2]) - r_shadow_bouncegrid_state.settings.spacing[2];
2476 cullmaxs[0] = max(originalstart[0], originalend[0]) + r_shadow_bouncegrid_state.settings.spacing[0];
2477 cullmaxs[1] = max(originalstart[1], originalend[1]) + r_shadow_bouncegrid_state.settings.spacing[1];
2478 cullmaxs[2] = max(originalstart[2], originalend[2]) + r_shadow_bouncegrid_state.settings.spacing[2];
2479 if (R_CullBox(cullmins, cullmaxs))
2483 // if the light path is going upward, reverse it - we always draw down.
2484 if (originalend[2] < originalstart[2])
2486 VectorCopy(originalend, start);
2487 VectorCopy(originalstart, end);
2491 VectorCopy(originalstart, start);
2492 VectorCopy(originalend, end);
2495 // transform to texture pixels
2496 start[0] = (start[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2497 start[1] = (start[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2498 start[2] = (start[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2499 end[0] = (end[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2500 end[1] = (end[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2501 end[2] = (end[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2503 // check if we need to grow the splatpaths array
2504 if (r_shadow_bouncegrid_state.maxsplatpaths <= r_shadow_bouncegrid_state.numsplatpaths)
2506 // double the limit, this will persist from frame to frame so we don't
2507 // make the same mistake each time
2508 r_shadow_bouncegrid_state.maxsplatpaths *= 2;
2509 if (r_shadow_bouncegrid_state.maxsplatpaths < 16384)
2510 r_shadow_bouncegrid_state.maxsplatpaths = 16384;
2511 r_shadow_bouncegrid_state.splatpaths = (r_shadow_bouncegrid_splatpath_t *)Mem_Realloc(r_main_mempool, r_shadow_bouncegrid_state.splatpaths, sizeof(r_shadow_bouncegrid_splatpath_t) * r_shadow_bouncegrid_state.maxsplatpaths);
2514 // divide a series of splats along the length using the maximum axis
2515 VectorSubtract(end, start, diff);
2516 // pick the best axis to trace along
2518 if (diff[1]*diff[1] > diff[bestaxis]*diff[bestaxis])
2520 if (diff[2]*diff[2] > diff[bestaxis]*diff[bestaxis])
2522 len = fabs(diff[bestaxis]);
2524 numsplats = (int)(floor(len + 0.5f));
2526 numsplats = bound(0, numsplats, 1024);
2528 VectorSubtract(originalstart, originalend, originaldir);
2529 VectorNormalize(originaldir);
2531 path = r_shadow_bouncegrid_state.splatpaths + r_shadow_bouncegrid_state.numsplatpaths++;
2532 VectorCopy(start, path->point);
2533 VectorScale(diff, ilen, path->step);
2534 VectorCopy(color, path->splatcolor);
2535 VectorCopy(originaldir, path->splatdir);
2536 path->splatsize_current = r_shadow_bouncegrid_state.settings.lightpathsize_initial + r_shadow_bouncegrid_state.settings.lightpathsize_conespread * distancetraveled * r_shadow_bouncegrid_state.ispacing[0];
2537 path->splatsize_perstep = r_shadow_bouncegrid_state.settings.lightpathsize_conespread;
2538 path->splatintensity = VectorLength(color);
2539 path->remainingsplats = numsplats;
2542 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
2544 qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
2551 // see if there are really any lights to render...
2552 if (enable && r_shadow_bouncegrid_static.integer)
2555 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2556 for (lightindex = 0;lightindex < range;lightindex++)
2558 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2559 if (!light || !(light->flags & flag))
2561 rtlight = &light->rtlight;
2562 // when static, we skip styled lights because they tend to change...
2563 if (rtlight->style > 0)
2565 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
2566 if (!VectorLength2(lightcolor))
2576 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
2578 qboolean s = r_shadow_bouncegrid_static.integer != 0;
2579 float spacing = bound(1.0f, s ? r_shadow_bouncegrid_static_spacing.value : r_shadow_bouncegrid_dynamic_spacing.value, 1024.0f);
2580 float quality = bound(0.0001f, (s ? r_shadow_bouncegrid_static_quality.value : r_shadow_bouncegrid_dynamic_quality.value), 1024.0f);
2581 float bounceminimumintensity = s ? r_shadow_bouncegrid_static_bounceminimumintensity.value : r_shadow_bouncegrid_dynamic_bounceminimumintensity.value;
2583 // prevent any garbage in alignment padded areas as we'll be using memcmp
2584 memset(settings, 0, sizeof(*settings));
2586 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
2587 settings->staticmode = s;
2588 settings->blur = r_shadow_bouncegrid_blur.integer != 0;
2589 settings->floatcolors = bound(0, r_shadow_bouncegrid_floatcolors.integer, 2);
2590 settings->lightpathsize_initial = bound(0.0f, r_shadow_bouncegrid_lightpathsize_initial.value, 1024.0f);
2591 settings->lightpathsize_conespread = bound(0.0f, r_shadow_bouncegrid_lightpathsize_conespread.value, 1024.0f);
2592 settings->bounceanglediffuse = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
2593 settings->directionalshading = (s ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_dynamic_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
2594 settings->dlightparticlemultiplier = s ? 0 : r_shadow_bouncegrid_dynamic_dlightparticlemultiplier.value;
2595 settings->hitmodels = s ? false : r_shadow_bouncegrid_dynamic_hitmodels.integer != 0;
2596 settings->includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
2597 settings->lightradiusscale = (s ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_dynamic_lightradiusscale.value);
2598 settings->maxbounce = (s ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_dynamic_maxbounce.integer);
2599 settings->particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
2600 settings->particleintensity = r_shadow_bouncegrid_particleintensity.value * (settings->directionalshading ? 4.0f : 1.0f) * 16384 / (spacing * spacing) / 262144.0f;
2601 settings->maxphotons = s ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_dynamic_maxphotons.integer;
2602 settings->energyperphoton = spacing * spacing / quality;
2603 settings->spacing[0] = spacing;
2604 settings->spacing[1] = spacing;
2605 settings->spacing[2] = spacing;
2606 settings->rng_type = r_shadow_bouncegrid_rng_type.integer;
2607 settings->rng_seed = r_shadow_bouncegrid_rng_seed.integer;
2608 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
2609 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
2610 settings->normalizevectors = r_shadow_bouncegrid_normalizevectors.integer != 0;
2612 // bound the values for sanity
2613 settings->maxphotons = bound(1, settings->maxphotons, 25000000);
2614 settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
2615 settings->maxbounce = bound(0, settings->maxbounce, 16);
2616 settings->spacing[0] = bound(1, settings->spacing[0], 512);
2617 settings->spacing[1] = bound(1, settings->spacing[1], 512);
2618 settings->spacing[2] = bound(1, settings->spacing[2], 512);
2621 static void R_Shadow_BounceGrid_UpdateSpacing(void)
2632 r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
2634 // get the spacing values
2635 spacing[0] = settings->spacing[0];
2636 spacing[1] = settings->spacing[1];
2637 spacing[2] = settings->spacing[2];
2638 ispacing[0] = 1.0f / spacing[0];
2639 ispacing[1] = 1.0f / spacing[1];
2640 ispacing[2] = 1.0f / spacing[2];
2642 // calculate texture size enclosing entire world bounds at the spacing
2643 if (r_refdef.scene.worldmodel)
2647 qboolean bounds_set = false;
2651 // calculate bounds enclosing world lights as they should be noticably tighter
2652 // than the world bounds on maps with unlit monster containers (see e1m7 etc)
2653 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2654 for (lightindex = 0;lightindex < range;lightindex++)
2656 const vec_t *rtlmins, *rtlmaxs;
2658 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2662 rtlight = &light->rtlight;
2663 rtlmins = rtlight->cullmins;
2664 rtlmaxs = rtlight->cullmaxs;
2668 VectorCopy(rtlmins, mins);
2669 VectorCopy(rtlmaxs, maxs);
2674 mins[0] = min(mins[0], rtlmins[0]);
2675 mins[1] = min(mins[1], rtlmins[1]);
2676 mins[2] = min(mins[2], rtlmins[2]);
2677 maxs[0] = max(maxs[0], rtlmaxs[0]);
2678 maxs[1] = max(maxs[1], rtlmaxs[1]);
2679 maxs[2] = max(maxs[2], rtlmaxs[2]);
2683 // limit to no larger than the world bounds
2684 mins[0] = max(mins[0], r_refdef.scene.worldmodel->normalmins[0]);
2685 mins[1] = max(mins[1], r_refdef.scene.worldmodel->normalmins[1]);
2686 mins[2] = max(mins[2], r_refdef.scene.worldmodel->normalmins[2]);
2687 maxs[0] = min(maxs[0], r_refdef.scene.worldmodel->normalmaxs[0]);
2688 maxs[1] = min(maxs[1], r_refdef.scene.worldmodel->normalmaxs[1]);
2689 maxs[2] = min(maxs[2], r_refdef.scene.worldmodel->normalmaxs[2]);
2691 VectorMA(mins, -2.0f, spacing, mins);
2692 VectorMA(maxs, 2.0f, spacing, maxs);
2696 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
2697 VectorSet(maxs, 1048576.0f, 1048576.0f, 1048576.0f);
2699 VectorSubtract(maxs, mins, size);
2700 // now we can calculate the resolution we want
2701 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2702 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2703 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2704 // figure out the exact texture size (honoring power of 2 if required)
2705 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2706 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2707 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2708 if (vid.support.arb_texture_non_power_of_two)
2710 resolution[0] = c[0];
2711 resolution[1] = c[1];
2712 resolution[2] = c[2];
2716 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2717 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2718 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2720 size[0] = spacing[0] * resolution[0];
2721 size[1] = spacing[1] * resolution[1];
2722 size[2] = spacing[2] * resolution[2];
2724 // if dynamic we may or may not want to use the world bounds
2725 // if the dynamic size is smaller than the world bounds, use it instead
2726 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]))
2728 // we know the resolution we want
2729 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
2730 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
2731 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
2732 // now we can calculate the texture size (power of 2 if required)
2733 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2734 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2735 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2736 if (vid.support.arb_texture_non_power_of_two)
2738 resolution[0] = c[0];
2739 resolution[1] = c[1];
2740 resolution[2] = c[2];
2744 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2745 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2746 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2748 size[0] = spacing[0] * resolution[0];
2749 size[1] = spacing[1] * resolution[1];
2750 size[2] = spacing[2] * resolution[2];
2751 // center the rendering on the view
2752 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2753 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2754 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2757 // recalculate the maxs in case the resolution was not satisfactory
2758 VectorAdd(mins, size, maxs);
2760 // check if this changed the texture size
2761 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);
2762 r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
2763 VectorCopy(mins, r_shadow_bouncegrid_state.mins);
2764 VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
2765 VectorCopy(size, r_shadow_bouncegrid_state.size);
2766 VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
2767 VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
2768 VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
2770 // reallocate pixels for this update if needed...
2771 r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
2772 r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
2773 r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
2774 numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
2775 if (r_shadow_bouncegrid_state.numpixels != numpixels)
2777 if (r_shadow_bouncegrid_state.texture) { R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL; }
2779 r_shadow_bouncegrid_state.highpixels = NULL;
2781 if (r_shadow_bouncegrid_state.blurpixels[0]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL; }
2782 if (r_shadow_bouncegrid_state.blurpixels[1]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL; }
2783 if (r_shadow_bouncegrid_state.u8pixels) { Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL; }
2784 if (r_shadow_bouncegrid_state.fp16pixels) { Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL; }
2785 if (r_shadow_bouncegrid_state.splatpaths) { Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL; }
2787 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2788 r_shadow_bouncegrid_state.numpixels = numpixels;
2791 // update the bouncegrid matrix to put it in the world properly
2792 memset(m, 0, sizeof(m));
2793 m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
2794 m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
2795 m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
2796 m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
2797 m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
2798 m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
2800 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
2803 // enumerate world rtlights and sum the overall amount of light in the world,
2804 // from that we can calculate a scaling factor to fairly distribute photons
2805 // to all the lights
2807 // this modifies rtlight->photoncolor and rtlight->photons
2808 static void R_Shadow_BounceGrid_AssignPhotons(r_shadow_bouncegrid_settings_t *settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
2810 float normalphotonscaling;
2811 float photonscaling;
2812 float photonintensity;
2813 float photoncount = 0.0f;
2814 float lightintensity;
2820 unsigned int lightindex;
2823 normalphotonscaling = 1.0f / max(0.0001f, settings->energyperphoton);
2824 for (lightindex = 0;lightindex < range2;lightindex++)
2826 if (lightindex < range)
2828 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2831 rtlight = &light->rtlight;
2832 VectorClear(rtlight->bouncegrid_photoncolor);
2833 rtlight->bouncegrid_photons = 0;
2834 rtlight->bouncegrid_hits = 0;
2835 rtlight->bouncegrid_traces = 0;
2836 rtlight->bouncegrid_effectiveradius = 0;
2837 if (!(light->flags & flag))
2839 if (settings->staticmode)
2841 // when static, we skip styled lights because they tend to change...
2842 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2845 else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
2850 rtlight = r_refdef.scene.lights[lightindex - range];
2851 VectorClear(rtlight->bouncegrid_photoncolor);
2852 rtlight->bouncegrid_photons = 0;
2853 rtlight->bouncegrid_hits = 0;
2854 rtlight->bouncegrid_traces = 0;
2855 rtlight->bouncegrid_effectiveradius = 0;
2857 // draw only visible lights (major speedup)
2858 radius = rtlight->radius * settings->lightradiusscale;
2859 cullmins[0] = rtlight->shadoworigin[0] - radius;
2860 cullmins[1] = rtlight->shadoworigin[1] - radius;
2861 cullmins[2] = rtlight->shadoworigin[2] - radius;
2862 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2863 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2864 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2865 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2866 if (!settings->staticmode)
2868 // skip if the expanded light box does not touch any visible leafs
2869 if (r_refdef.scene.worldmodel
2870 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2871 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2873 // skip if the expanded light box is not visible to traceline
2874 // note that PrepareLight already did this check but for a smaller box, so we
2875 // end up casting more traces per frame per light when using bouncegrid, which
2876 // is probably fine (and they use the same timer)
2877 if (r_shadow_culllights_trace.integer)
2879 if (rtlight->trace_timer != realtime && R_CanSeeBox(rtlight->trace_timer == 0 ? r_shadow_culllights_trace_tempsamples.integer : r_shadow_culllights_trace_samples.integer, r_shadow_culllights_trace_eyejitter.value, r_shadow_culllights_trace_enlarge.value, r_refdef.view.origin, rtlight->cullmins, rtlight->cullmaxs))
2880 rtlight->trace_timer = realtime;
2881 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
2884 // skip if expanded light box is offscreen
2885 if (R_CullBox(cullmins, cullmaxs))
2887 // skip if overall light intensity is zero
2888 if (w * VectorLength2(rtlight->color) == 0.0f)
2891 // a light that does not emit any light before style is applied, can be
2892 // skipped entirely (it may just be a corona)
2893 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2895 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2896 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2897 // skip lights that will emit no photons
2898 if (!VectorLength2(rtlight->bouncegrid_photoncolor))
2900 // shoot particles from this light
2901 // use a calculation for the number of particles that will not
2902 // vary with lightstyle, otherwise we get randomized particle
2903 // distribution, the seeded random is only consistent for a
2904 // consistent number of particles on this light...
2905 s = rtlight->radius;
2906 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2907 if (lightindex >= range)
2908 lightintensity *= settings->dlightparticlemultiplier;
2909 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2910 photoncount += rtlight->bouncegrid_photons;
2911 VectorScale(rtlight->bouncegrid_photoncolor, settings->particleintensity * settings->energyperphoton, rtlight->bouncegrid_photoncolor);
2912 // if the lightstyle happens to be off right now, we can skip actually
2913 // firing the photons, but we did have to count them in the total.
2914 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2915 // rtlight->bouncegrid_photons = 0;
2917 // the user provided an energyperphoton value which we try to use
2918 // if that results in too many photons to shoot this frame, then we cap it
2919 // which causes photons to appear/disappear from frame to frame, so we don't
2920 // like doing that in the typical case
2921 photonscaling = 1.0f;
2922 photonintensity = 1.0f;
2923 if (photoncount > settings->maxphotons)
2925 photonscaling = settings->maxphotons / photoncount;
2926 photonintensity = 1.0f / photonscaling;
2929 // modify the lights to reflect our computed scaling
2930 for (lightindex = 0; lightindex < range2; lightindex++)
2932 if (lightindex < range)
2934 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2937 rtlight = &light->rtlight;
2940 rtlight = r_refdef.scene.lights[lightindex - range];
2941 rtlight->bouncegrid_photons *= photonscaling;
2942 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2946 static int R_Shadow_BounceGrid_SplatPathCompare(const void *pa, const void *pb)
2948 r_shadow_bouncegrid_splatpath_t *a = (r_shadow_bouncegrid_splatpath_t *)pa;
2949 r_shadow_bouncegrid_splatpath_t *b = (r_shadow_bouncegrid_splatpath_t *)pb;
2950 // we only really care about sorting by Z
2951 if (a->point[2] < b->point[2])
2953 if (a->point[2] > b->point[2])
2958 static void R_Shadow_BounceGrid_ClearPixels(void)
2960 // clear the highpixels array we'll be accumulating into
2961 if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2962 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2963 if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2964 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2965 r_shadow_bouncegrid_state.highpixels_index = 0;
2966 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2967 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2970 static void R_Shadow_BounceGrid_PerformSplats(void)
2972 r_shadow_bouncegrid_splatpath_t *splatpaths = r_shadow_bouncegrid_state.splatpaths;
2973 r_shadow_bouncegrid_splatpath_t *splatpath;
2974 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2975 int numsplatpaths = r_shadow_bouncegrid_state.numsplatpaths;
2980 vec_t lightpathsize_current;
2981 vec_t lightpathsize_perstep;
2982 float splatcolor[32];
2984 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2985 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2989 // hush warnings about uninitialized data - pixelbands doesn't change but...
2990 memset(splatcolor, 0, sizeof(splatcolor));
2992 // we use this a lot, so get a local copy
2993 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2995 // sort the splats before we execute them, to reduce cache misses
2996 if (r_shadow_bouncegrid_sortlightpaths.integer)
2997 qsort(splatpaths, numsplatpaths, sizeof(*splatpaths), R_Shadow_BounceGrid_SplatPathCompare);
2999 splatpath = splatpaths;
3000 for (splatindex = 0;splatindex < numsplatpaths;splatindex++, splatpath++)
3002 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
3003 // accumulate average shotcolor
3004 VectorCopy(splatpath->splatdir, dir);
3005 splatcolor[ 0] = splatpath->splatcolor[0];
3006 splatcolor[ 1] = splatpath->splatcolor[1];
3007 splatcolor[ 2] = splatpath->splatcolor[2];
3008 splatcolor[ 3] = 0.0f;
3011 // store bentnormal in case the shader has a use for it,
3012 // bentnormal is an intensity-weighted average of the directions,
3013 // and will be normalized on conversion to texture pixels.
3014 splatcolor[ 4] = dir[0] * splatpath->splatintensity;
3015 splatcolor[ 5] = dir[1] * splatpath->splatintensity;
3016 splatcolor[ 6] = dir[2] * splatpath->splatintensity;
3017 splatcolor[ 7] = splatpath->splatintensity;
3018 // for each color component (R, G, B) calculate the amount that a
3019 // direction contributes
3020 splatcolor[ 8] = splatcolor[0] * max(0.0f, dir[0]);
3021 splatcolor[ 9] = splatcolor[0] * max(0.0f, dir[1]);
3022 splatcolor[10] = splatcolor[0] * max(0.0f, dir[2]);
3023 splatcolor[11] = 0.0f;
3024 splatcolor[12] = splatcolor[1] * max(0.0f, dir[0]);
3025 splatcolor[13] = splatcolor[1] * max(0.0f, dir[1]);
3026 splatcolor[14] = splatcolor[1] * max(0.0f, dir[2]);
3027 splatcolor[15] = 0.0f;
3028 splatcolor[16] = splatcolor[2] * max(0.0f, dir[0]);
3029 splatcolor[17] = splatcolor[2] * max(0.0f, dir[1]);
3030 splatcolor[18] = splatcolor[2] * max(0.0f, dir[2]);
3031 splatcolor[19] = 0.0f;
3032 // and do the same for negative directions
3033 splatcolor[20] = splatcolor[0] * max(0.0f, -dir[0]);
3034 splatcolor[21] = splatcolor[0] * max(0.0f, -dir[1]);
3035 splatcolor[22] = splatcolor[0] * max(0.0f, -dir[2]);
3036 splatcolor[23] = 0.0f;
3037 splatcolor[24] = splatcolor[1] * max(0.0f, -dir[0]);
3038 splatcolor[25] = splatcolor[1] * max(0.0f, -dir[1]);
3039 splatcolor[26] = splatcolor[1] * max(0.0f, -dir[2]);
3040 splatcolor[27] = 0.0f;
3041 splatcolor[28] = splatcolor[2] * max(0.0f, -dir[0]);
3042 splatcolor[29] = splatcolor[2] * max(0.0f, -dir[1]);
3043 splatcolor[30] = splatcolor[2] * max(0.0f, -dir[2]);
3044 splatcolor[31] = 0.0f;
3046 // calculate the number of steps we need to traverse this distance
3047 VectorCopy(splatpath->point, steppos);
3048 VectorCopy(splatpath->step, stepdelta);
3049 numsteps = splatpath->remainingsplats;
3050 lightpathsize_current = splatpath->splatsize_current + 1.0f; // add 1.0 for the gradient fade around the sphere
3051 lightpathsize_perstep = splatpath->splatsize_perstep;
3052 for (step = 0;step < numsteps;step++)
3054 // the middle row/column/layer of each splat are full intensity
3057 if (lightpathsize_current > MAXBOUNCEGRIDSPLATSIZE)
3058 lightpathsize_current = MAXBOUNCEGRIDSPLATSIZE;
3059 splatmins[0] = max(1.0f, steppos[0] - lightpathsize_current * 0.5f);
3060 splatmins[1] = max(1.0f, steppos[1] - lightpathsize_current * 0.5f);
3061 splatmins[2] = max(1.0f, steppos[2] - lightpathsize_current * 0.5f);
3062 splatmaxs[0] = min(steppos[0] + lightpathsize_current * 0.5f, resolution[0] - 1.0f);
3063 splatmaxs[1] = min(steppos[1] + lightpathsize_current * 0.5f, resolution[1] - 1.0f);
3064 splatmaxs[2] = min(steppos[2] + lightpathsize_current * 0.5f, resolution[2] - 1.0f);
3065 if (splatmaxs[0] > splatmins[0] && splatmaxs[1] > splatmins[1] && splatmaxs[2] > splatmins[2])
3067 // it is within bounds... do the real work now
3068 int xi, yi, zi, band, row;
3072 float colorscale = 1.0f / lightpathsize_current;
3073 r_refdef.stats[r_stat_bouncegrid_splats]++;
3074 // accumulate light onto the pixels
3075 for (zi = (int)floor(splatmins[2]);zi < splatmaxs[2];zi++)
3077 pixelpos[2] = zi + 0.5f;
3078 for (yi = (int)floor(splatmins[1]); yi < splatmaxs[1]; yi++)
3080 pixelpos[1] = yi + 0.5f;
3081 row = (zi*resolution[1] + yi)*resolution[0];
3082 for (xi = (int)floor(splatmins[0]); xi < splatmaxs[0]; xi++)
3084 pixelpos[0] = xi + 0.5f;
3085 // simple radial antialiased sphere - linear gradient fade over 1 pixel from the edge
3086 w = lightpathsize_current - VectorDistance(pixelpos, steppos);
3092 p = highpixels + 4 * (row + xi);
3093 for (band = 0; band < pixelbands; band++, p += pixelsperband * 4)
3095 // add to the pixel color
3096 p[0] += splatcolor[band * 4 + 0] * w;
3097 p[1] += splatcolor[band * 4 + 1] * w;
3098 p[2] += splatcolor[band * 4 + 2] * w;
3099 p[3] += splatcolor[band * 4 + 3] * w;
3106 VectorAdd(steppos, stepdelta, steppos);
3107 lightpathsize_current += lightpathsize_perstep;
3112 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
3114 const float *inpixel;
3116 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
3119 unsigned int x, y, z;
3120 unsigned int resolution[3];
3121 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3122 for (pixelband = 0;pixelband < pixelbands;pixelband++)
3124 for (z = 1;z < resolution[2]-1;z++)
3126 for (y = 1;y < resolution[1]-1;y++)
3129 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3130 inpixel = inpixels + 4*index;
3131 outpixel = outpixels + 4*index;
3132 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
3134 outpixel[0] = (inpixel[0] + inpixel[ off] + inpixel[0-off]) * (1.0f / 3.0);
3135 outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
3136 outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
3137 outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
3144 static void R_Shadow_BounceGrid_BlurPixels(void)
3147 unsigned int resolution[3];
3149 if (!r_shadow_bouncegrid_state.settings.blur)
3152 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3154 pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3155 pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
3156 pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3157 pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
3160 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
3162 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
3164 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
3166 // toggle the state, highpixels now points to pixels[3] result
3167 r_shadow_bouncegrid_state.highpixels_index ^= 1;
3168 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3171 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
3173 int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
3174 unsigned char *pixelsbgra8 = NULL;
3175 unsigned char *pixelbgra8;
3176 unsigned short *pixelsrgba16f = NULL;
3177 unsigned short *pixelrgba16f;
3178 float *pixelsrgba32f = NULL;
3179 float *highpixels = r_shadow_bouncegrid_state.highpixels;
3182 unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
3183 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
3184 unsigned int pixelband;
3185 unsigned int x, y, z;
3186 unsigned int index, bandindex;
3187 unsigned int resolution[3];
3189 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3191 if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
3193 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3194 r_shadow_bouncegrid_state.texture = NULL;
3197 // if bentnormals exist, we need to normalize and bias them for the shader
3201 for (z = 0;z < resolution[2]-1;z++)
3203 for (y = 0;y < resolution[1]-1;y++)
3206 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3207 highpixel = highpixels + 4*index;
3208 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3210 // only convert pixels that were hit by photons
3211 if (highpixel[3] != 0.0f)
3212 VectorNormalize(highpixel);
3213 VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
3214 highpixel[pixelsperband * 4 + 3] = 1.0f;
3220 // start by clearing the pixels array - we won't be writing to all of it
3222 // then process only the pixels that have at least some color, skipping
3223 // the higher bands for speed on pixels that are black
3224 switch (floatcolors)
3227 if (r_shadow_bouncegrid_state.u8pixels == NULL)
3228 r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
3229 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
3230 for (pixelband = 0;pixelband < pixelbands;pixelband++)
3233 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
3235 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
3237 for (z = 1;z < resolution[2]-1;z++)
3239 for (y = 1;y < resolution[1]-1;y++)
3243 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3244 highpixel = highpixels + 4*index;
3245 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3247 // only convert pixels that were hit by photons
3248 if (VectorLength2(highpixel))
3250 // normalize the bentnormal now
3253 VectorNormalize(highpixel + pixelsperband * 4);
3254 highpixel[pixelsperband * 4 + 3] = 1.0f;
3256 // process all of the pixelbands for this pixel
3257 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3259 pixelbgra8 = pixelsbgra8 + 4*bandindex;
3260 bandpixel = highpixels + 4*bandindex;
3261 c[0] = (int)(bandpixel[0]*256.0f);
3262 c[1] = (int)(bandpixel[1]*256.0f);
3263 c[2] = (int)(bandpixel[2]*256.0f);
3264 c[3] = (int)(bandpixel[3]*256.0f);
3265 pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
3266 pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
3267 pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
3268 pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
3275 if (!r_shadow_bouncegrid_state.createtexture)
3276 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3278 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);
3281 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
3282 r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3283 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
3284 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3285 for (z = 1;z < resolution[2]-1;z++)
3287 for (y = 1;y < resolution[1]-1;y++)
3291 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3292 highpixel = highpixels + 4*index;
3293 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3295 // only convert pixels that were hit by photons
3296 if (VectorLength2(highpixel))
3298 // process all of the pixelbands for this pixel
3299 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3301 // time to have fun with IEEE 754 bit hacking...
3304 unsigned int raw[4];
3306 pixelrgba16f = pixelsrgba16f + 4*bandindex;
3307 bandpixel = highpixels + 4*bandindex;
3308 VectorCopy4(bandpixel, u.f);
3309 VectorCopy4(u.raw, c);
3310 // this math supports negative numbers, snaps denormals to zero
3311 //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
3312 //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
3313 //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
3314 //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
3315 // this math does not support negative
3316 pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
3317 pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
3318 pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
3319 pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
3326 if (!r_shadow_bouncegrid_state.createtexture)
3327 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3329 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);
3332 // our native format happens to match, so this is easy.
3333 pixelsrgba32f = highpixels;
3335 if (!r_shadow_bouncegrid_state.createtexture)
3336 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3338 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);
3342 r_shadow_bouncegrid_state.lastupdatetime = realtime;
3345 static void R_Shadow_BounceGrid_TracePhotons(r_shadow_bouncegrid_settings_t settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
3347 vec3_t bouncerandom[10];
3350 int hitsupercontentsmask;
3351 int skipsupercontentsmask;
3352 int skipmaterialflagsmask;
3356 float bounceminimumintensity2;
3358 //trace_t cliptrace2;
3359 //trace_t cliptrace3;
3360 unsigned int lightindex;
3362 randomseed_t randomseed;
3364 vec3_t baseshotcolor;
3370 vec_t distancetraveled;
3374 // compute a seed for the unstable random modes
3375 Math_RandomSeed_FromInts(&randomseed, 0, 0, 0, realtime * 1000.0);
3376 seed = realtime * 1000.0;
3378 r_shadow_bouncegrid_state.numsplatpaths = 0;
3380 // figure out what we want to interact with
3381 if (settings.hitmodels)
3382 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
3384 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
3385 skipsupercontentsmask = 0;
3386 skipmaterialflagsmask = MATERIALFLAGMASK_TRANSLUCENT;
3387 maxbounce = settings.maxbounce;
3389 for (lightindex = 0;lightindex < range2;lightindex++)
3391 if (lightindex < range)
3393 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3396 rtlight = &light->rtlight;
3399 rtlight = r_refdef.scene.lights[lightindex - range];
3400 // note that this code used to keep track of residual photons and
3401 // distribute them evenly to achieve exactly a desired photon count,
3402 // but that caused unwanted flickering in dynamic mode
3403 shootparticles = (int)floor(rtlight->bouncegrid_photons);
3404 // skip if we won't be shooting any photons
3405 if (!shootparticles)
3407 radius = rtlight->radius * settings.lightradiusscale;
3408 //s = settings.particleintensity / shootparticles;
3409 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
3410 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
3411 if (VectorLength2(baseshotcolor) <= 0.0f)
3413 r_refdef.stats[r_stat_bouncegrid_lights]++;
3414 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
3415 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
3416 bounceminimumintensity2 = VectorLength(baseshotcolor) * settings.bounceminimumintensity2;
3418 // for seeded random we start the RNG with the position of the light
3419 if (settings.rng_seed >= 0)
3427 u.f[0] = rtlight->shadoworigin[0];
3428 u.f[1] = rtlight->shadoworigin[1];
3429 u.f[2] = rtlight->shadoworigin[2];
3431 switch (settings.rng_type)
3435 // we have to shift the seed provided by the user because the result must be odd
3436 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3] ^ (settings.rng_seed << 1));
3439 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3] ^ settings.rng_seed;
3444 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
3446 VectorCopy(baseshotcolor, shotcolor);
3447 VectorCopy(rtlight->shadoworigin, clipstart);
3448 switch (settings.rng_type)
3452 VectorLehmerRandom(&randomseed, clipend);
3453 if (settings.bounceanglediffuse)
3455 // we want random to be stable, so we still have to do all the random we would have done
3456 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3457 VectorLehmerRandom(&randomseed, bouncerandom[bouncecount]);
3461 VectorCheeseRandom(seed, clipend);
3462 if (settings.bounceanglediffuse)
3464 // we want random to be stable, so we still have to do all the random we would have done
3465 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3466 VectorCheeseRandom(seed, bouncerandom[bouncecount]);
3471 // we want a uniform distribution spherically, not merely within the sphere
3472 if (settings.normalizevectors)
3473 VectorNormalize(clipend);
3475 VectorMA(clipstart, radius, clipend, clipend);
3476 distancetraveled = 0.0f;
3477 for (bouncecount = 0;;bouncecount++)
3479 r_refdef.stats[r_stat_bouncegrid_traces]++;
3480 rtlight->bouncegrid_traces++;
3481 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
3482 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
3483 if (settings.staticmode || settings.rng_seed < 0)
3485 // static mode fires a LOT of rays but none of them are identical, so they are not cached
3486 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
3487 cliptrace = CL_TraceLine(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), NULL, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, collision_extendmovelength.value, true, false, NULL, true, true);
3491 // dynamic mode fires many rays and most will match the cache from the previous frame
3492 cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
3494 if (bouncecount > 0 || settings.includedirectlighting)
3497 VectorCopy(cliptrace.endpos, hitpos);
3498 R_Shadow_BounceGrid_AddSplatPath(clipstart, hitpos, shotcolor, distancetraveled);
3500 distancetraveled += VectorDistance(clipstart, cliptrace.endpos);
3501 s = VectorDistance(rtlight->shadoworigin, cliptrace.endpos);
3502 if (rtlight->bouncegrid_effectiveradius < s)
3503 rtlight->bouncegrid_effectiveradius = s;
3504 if (cliptrace.fraction >= 1.0f)
3506 r_refdef.stats[r_stat_bouncegrid_hits]++;
3507 rtlight->bouncegrid_hits++;
3508 if (bouncecount >= maxbounce)
3510 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
3511 // also clamp the resulting color to never add energy, even if the user requests extreme values
3512 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
3513 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
3515 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
3516 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
3517 surfcolor[0] = min(surfcolor[0], 1.0f);
3518 surfcolor[1] = min(surfcolor[1], 1.0f);
3519 surfcolor[2] = min(surfcolor[2], 1.0f);
3520 VectorMultiply(shotcolor, surfcolor, shotcolor);
3521 if (VectorLength2(shotcolor) <= bounceminimumintensity2)
3523 r_refdef.stats[r_stat_bouncegrid_bounces]++;
3524 if (settings.bounceanglediffuse)
3526 // random direction, primarily along plane normal
3527 s = VectorDistance(cliptrace.endpos, clipend);
3528 VectorMA(cliptrace.plane.normal, 0.95f, bouncerandom[bouncecount], clipend);
3529 VectorNormalize(clipend);
3530 VectorScale(clipend, s, clipend);
3534 // reflect the remaining portion of the line across plane normal
3535 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
3536 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
3538 // calculate the new line start and end
3539 VectorCopy(cliptrace.endpos, clipstart);
3540 VectorAdd(clipstart, clipend, clipend);
3546 void R_Shadow_UpdateBounceGridTexture(void)
3548 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3549 r_shadow_bouncegrid_settings_t settings;
3550 qboolean enable = false;
3551 qboolean settingschanged;
3552 unsigned int range; // number of world lights
3553 unsigned int range1; // number of dynamic lights (or zero if disabled)
3554 unsigned int range2; // range+range1
3556 enable = R_Shadow_BounceGrid_CheckEnable(flag);
3558 R_Shadow_BounceGrid_GenerateSettings(&settings);
3560 // changing intensity does not require an update
3561 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
3563 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
3565 // when settings change, we free everything as it is just simpler that way.
3566 if (settingschanged || !enable)
3568 // not enabled, make sure we free anything we don't need anymore.
3569 if (r_shadow_bouncegrid_state.texture)
3571 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3572 r_shadow_bouncegrid_state.texture = NULL;
3574 r_shadow_bouncegrid_state.highpixels = NULL;
3575 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
3576 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
3577 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
3578 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
3579 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
3580 r_shadow_bouncegrid_state.maxsplatpaths = 0;
3581 r_shadow_bouncegrid_state.numpixels = 0;
3582 r_shadow_bouncegrid_state.directional = false;
3588 // if all the settings seem identical to the previous update, return
3589 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
3592 // store the new settings
3593 r_shadow_bouncegrid_state.settings = settings;
3595 R_Shadow_BounceGrid_UpdateSpacing();
3597 // get the range of light numbers we'll be looping over:
3598 // range = static lights
3599 // range1 = dynamic lights (optional)
3600 // range2 = range + range1
3601 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3602 range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
3603 range2 = range + range1;
3605 // calculate weighting factors for distributing photons among the lights
3606 R_Shadow_BounceGrid_AssignPhotons(&settings, range, range1, range2, flag);
3608 // trace the photons from lights and accumulate illumination
3609 R_Shadow_BounceGrid_TracePhotons(settings, range, range1, range2, flag);
3611 // clear the texture
3612 R_Shadow_BounceGrid_ClearPixels();
3614 // accumulate the light splatting into texture
3615 R_Shadow_BounceGrid_PerformSplats();
3617 // apply a mild blur filter to the texture
3618 R_Shadow_BounceGrid_BlurPixels();
3620 // convert the pixels to lower precision and upload the texture
3621 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
3623 // after we compute the static lighting we don't need to keep the highpixels array around
3624 if (settings.staticmode)
3626 r_shadow_bouncegrid_state.highpixels = NULL;
3627 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
3628 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
3629 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
3630 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
3631 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
3632 r_shadow_bouncegrid_state.maxsplatpaths = 0;
3636 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
3638 R_Shadow_RenderMode_Reset();
3639 GL_BlendFunc(GL_ONE, GL_ONE);
3640 GL_DepthRange(0, 1);
3641 GL_DepthTest(r_showshadowvolumes.integer < 2);
3642 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
3643 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
3644 GL_CullFace(GL_NONE);
3645 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
3648 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
3650 R_Shadow_RenderMode_Reset();
3651 GL_BlendFunc(GL_ONE, GL_ONE);
3652 GL_DepthRange(0, 1);
3653 GL_DepthTest(r_showlighting.integer < 2);
3654 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
3656 GL_DepthFunc(GL_EQUAL);
3657 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
3658 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
3661 void R_Shadow_RenderMode_End(void)
3663 R_Shadow_RenderMode_Reset();
3664 R_Shadow_RenderMode_ActiveLight(NULL);
3666 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3667 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3670 int bboxedges[12][2] =
3689 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
3691 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
3693 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
3694 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
3695 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
3696 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
3699 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
3700 return true; // invisible
3701 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
3702 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
3703 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
3704 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
3705 r_refdef.stats[r_stat_lights_scissored]++;
3709 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
3712 const float *vertex3f;
3713 const float *normal3f;
3715 float dist, dot, distintensity, shadeintensity, v[3], n[3];
3716 switch (r_shadow_rendermode)
3718 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3719 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3720 if (VectorLength2(diffusecolor) > 0)
3722 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)
3724 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3725 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3726 if ((dot = DotProduct(n, v)) < 0)
3728 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3729 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
3732 VectorCopy(ambientcolor, color4f);
3733 if (r_refdef.fogenabled)
3736 f = RSurf_FogVertex(vertex3f);
3737 VectorScale(color4f, f, color4f);
3744 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3746 VectorCopy(ambientcolor, color4f);
3747 if (r_refdef.fogenabled)
3750 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3751 f = RSurf_FogVertex(vertex3f);
3752 VectorScale(color4f + 4*i, f, color4f);
3758 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3759 if (VectorLength2(diffusecolor) > 0)
3761 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)
3763 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3764 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3766 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3767 if ((dot = DotProduct(n, v)) < 0)
3769 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3770 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3771 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3772 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3776 color4f[0] = ambientcolor[0] * distintensity;
3777 color4f[1] = ambientcolor[1] * distintensity;
3778 color4f[2] = ambientcolor[2] * distintensity;
3780 if (r_refdef.fogenabled)
3783 f = RSurf_FogVertex(vertex3f);
3784 VectorScale(color4f, f, color4f);
3788 VectorClear(color4f);
3794 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3796 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3797 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3799 color4f[0] = ambientcolor[0] * distintensity;
3800 color4f[1] = ambientcolor[1] * distintensity;
3801 color4f[2] = ambientcolor[2] * distintensity;
3802 if (r_refdef.fogenabled)
3805 f = RSurf_FogVertex(vertex3f);
3806 VectorScale(color4f, f, color4f);
3810 VectorClear(color4f);
3815 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3816 if (VectorLength2(diffusecolor) > 0)
3818 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)
3820 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3821 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3823 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3824 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3825 if ((dot = DotProduct(n, v)) < 0)
3827 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3828 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3829 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3830 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3834 color4f[0] = ambientcolor[0] * distintensity;
3835 color4f[1] = ambientcolor[1] * distintensity;
3836 color4f[2] = ambientcolor[2] * distintensity;
3838 if (r_refdef.fogenabled)
3841 f = RSurf_FogVertex(vertex3f);
3842 VectorScale(color4f, f, color4f);
3846 VectorClear(color4f);
3852 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3854 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3855 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3857 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3858 color4f[0] = ambientcolor[0] * distintensity;
3859 color4f[1] = ambientcolor[1] * distintensity;
3860 color4f[2] = ambientcolor[2] * distintensity;
3861 if (r_refdef.fogenabled)
3864 f = RSurf_FogVertex(vertex3f);
3865 VectorScale(color4f, f, color4f);
3869 VectorClear(color4f);
3879 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3881 // used to display how many times a surface is lit for level design purposes
3882 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3883 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3887 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const float ambientcolor[3], const float diffusecolor[3], const float specularcolor[3])
3889 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3890 R_SetupShader_Surface(ambientcolor, diffusecolor, specularcolor, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
3894 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3901 int newnumtriangles;
3905 int maxtriangles = 1024;
3906 int newelements[1024*3];
3907 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3908 for (renders = 0;renders < 4;renders++)
3913 newnumtriangles = 0;
3915 // due to low fillrate on the cards this vertex lighting path is
3916 // designed for, we manually cull all triangles that do not
3917 // contain a lit vertex
3918 // this builds batches of triangles from multiple surfaces and
3919 // renders them at once
3920 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3922 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3924 if (newnumtriangles)
3926 newfirstvertex = min(newfirstvertex, e[0]);
3927 newlastvertex = max(newlastvertex, e[0]);
3931 newfirstvertex = e[0];
3932 newlastvertex = e[0];
3934 newfirstvertex = min(newfirstvertex, e[1]);
3935 newlastvertex = max(newlastvertex, e[1]);
3936 newfirstvertex = min(newfirstvertex, e[2]);
3937 newlastvertex = max(newlastvertex, e[2]);
3943 if (newnumtriangles >= maxtriangles)
3945 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3946 newnumtriangles = 0;
3952 if (newnumtriangles >= 1)
3954 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3957 // if we couldn't find any lit triangles, exit early
3960 // now reduce the intensity for the next overbright pass
3961 // we have to clamp to 0 here incase the drivers have improper
3962 // handling of negative colors
3963 // (some old drivers even have improper handling of >1 color)
3965 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3967 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3969 c[0] = max(0, c[0] - 1);
3970 c[1] = max(0, c[1] - 1);
3971 c[2] = max(0, c[2] - 1);
3983 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const float ambientcolor[3], const float diffusecolor[3])
3985 // OpenGL 1.1 path (anything)
3986 float ambientcolorbase[3], diffusecolorbase[3];
3987 float ambientcolorpants[3], diffusecolorpants[3];
3988 float ambientcolorshirt[3], diffusecolorshirt[3];
3989 const float *surfacepants = rsurface.texture->render_colormap_pants;
3990 const float *surfaceshirt = rsurface.texture->render_colormap_shirt;
3991 rtexture_t *basetexture = rsurface.texture->basetexture;
3992 rtexture_t *pantstexture = rsurface.texture->pantstexture;
3993 rtexture_t *shirttexture = rsurface.texture->shirttexture;
3994 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3995 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3996 VectorCopy(ambientcolor, ambientcolorbase);
3997 VectorCopy(diffusecolor, diffusecolorbase);
3998 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3999 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
4000 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
4001 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
4002 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (VectorLength2(diffusecolor) > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
4003 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
4004 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4005 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
4006 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
4007 R_Mesh_TexBind(0, basetexture);
4008 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
4009 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
4010 switch(r_shadow_rendermode)
4012 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
4013 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
4014 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
4015 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
4016 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4018 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
4019 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
4020 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
4021 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
4022 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4024 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
4025 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
4026 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
4027 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
4028 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4030 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
4035 //R_Mesh_TexBind(0, basetexture);
4036 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
4039 R_Mesh_TexBind(0, pantstexture);
4040 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
4044 R_Mesh_TexBind(0, shirttexture);
4045 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
4049 extern cvar_t gl_lightmaps;
4050 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
4053 float ambientcolor[3], diffusecolor[3], specularcolor[3];
4054 VectorM(rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient, rsurface.texture->render_rtlight_diffuse, ambientcolor);
4055 VectorM(rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient), rsurface.texture->render_rtlight_diffuse, diffusecolor);
4056 VectorM(rsurface.rtlight->specularscale, rsurface.texture->render_rtlight_specular, specularcolor);
4057 if (!r_shadow_usenormalmap.integer)
4059 VectorMAM(1.0f, ambientcolor, 1.0f, diffusecolor, ambientcolor);
4060 VectorClear(diffusecolor);
4061 VectorClear(specularcolor);
4063 VectorMultiply(ambientcolor, rsurface.rtlight->currentcolor, ambientcolor);
4064 VectorMultiply(diffusecolor, rsurface.rtlight->currentcolor, diffusecolor);
4065 VectorMultiply(specularcolor, rsurface.rtlight->currentcolor, specularcolor);
4066 if (VectorLength2(ambientcolor) + VectorLength2(diffusecolor) + VectorLength2(specularcolor) < (1.0f / 1048576.0f))
4068 negated = (rsurface.rtlight->currentcolor[0] + rsurface.rtlight->currentcolor[1] + rsurface.rtlight->currentcolor[2] < 0) && vid.support.ext_blend_subtract;
4071 VectorNegate(ambientcolor, ambientcolor);
4072 VectorNegate(diffusecolor, diffusecolor);
4073 VectorNegate(specularcolor, specularcolor);
4074 GL_BlendEquationSubtract(true);
4076 RSurf_SetupDepthAndCulling();
4077 switch (r_shadow_rendermode)
4079 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
4080 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
4081 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
4083 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
4084 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, ambientcolor, diffusecolor, specularcolor);
4086 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
4087 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
4088 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
4089 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
4090 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, ambientcolor, diffusecolor);
4093 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
4097 GL_BlendEquationSubtract(false);
4100 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)
4102 matrix4x4_t tempmatrix = *matrix;
4103 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
4105 // if this light has been compiled before, free the associated data
4106 R_RTLight_Uncompile(rtlight);
4108 // clear it completely to avoid any lingering data
4109 memset(rtlight, 0, sizeof(*rtlight));
4111 // copy the properties
4112 rtlight->matrix_lighttoworld = tempmatrix;
4113 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
4114 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
4115 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
4116 VectorCopy(color, rtlight->color);
4117 rtlight->cubemapname[0] = 0;
4118 if (cubemapname && cubemapname[0])
4119 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
4120 rtlight->shadow = shadow;
4121 rtlight->corona = corona;
4122 rtlight->style = style;
4123 rtlight->isstatic = isstatic;
4124 rtlight->coronasizescale = coronasizescale;
4125 rtlight->ambientscale = ambientscale;
4126 rtlight->diffusescale = diffusescale;
4127 rtlight->specularscale = specularscale;
4128 rtlight->flags = flags;
4130 // compute derived data
4131 //rtlight->cullradius = rtlight->radius;
4132 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
4133 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
4134 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
4135 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
4136 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
4137 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
4138 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
4141 // compiles rtlight geometry
4142 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
4143 void R_RTLight_Compile(rtlight_t *rtlight)
4146 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
4147 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
4148 entity_render_t *ent = r_refdef.scene.worldentity;
4149 dp_model_t *model = r_refdef.scene.worldmodel;
4150 unsigned char *data;
4153 // compile the light
4154 rtlight->compiled = true;
4155 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
4156 rtlight->static_numleafs = 0;
4157 rtlight->static_numleafpvsbytes = 0;
4158 rtlight->static_leaflist = NULL;
4159 rtlight->static_leafpvs = NULL;
4160 rtlight->static_numsurfaces = 0;
4161 rtlight->static_surfacelist = NULL;
4162 rtlight->static_shadowmap_receivers = 0x3F;
4163 rtlight->static_shadowmap_casters = 0x3F;
4164 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
4165 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
4166 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
4167 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
4168 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
4169 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
4171 if (model && model->GetLightInfo)
4173 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
4174 r_shadow_compilingrtlight = rtlight;
4175 R_FrameData_SetMark();
4176 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, rtlight->shadow == 0);
4177 R_FrameData_ReturnToMark();
4178 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
4179 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
4180 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
4181 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
4182 rtlight->static_numsurfaces = numsurfaces;
4183 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
4184 rtlight->static_numleafs = numleafs;
4185 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
4186 rtlight->static_numleafpvsbytes = numleafpvsbytes;
4187 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
4188 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
4189 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
4190 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
4191 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
4192 if (rtlight->static_numsurfaces)
4193 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
4194 if (rtlight->static_numleafs)
4195 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
4196 if (rtlight->static_numleafpvsbytes)
4197 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
4198 if (rtlight->static_numshadowtrispvsbytes)
4199 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
4200 if (rtlight->static_numlighttrispvsbytes)
4201 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
4202 R_FrameData_SetMark();
4203 switch (rtlight->shadowmode)
4205 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4206 if (model->CompileShadowMap && rtlight->shadow)
4207 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
4210 if (model->CompileShadowVolume && rtlight->shadow)
4211 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
4214 R_FrameData_ReturnToMark();
4215 // now we're done compiling the rtlight
4216 r_shadow_compilingrtlight = NULL;
4220 // use smallest available cullradius - box radius or light radius
4221 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
4222 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
4224 shadowzpasstris = 0;
4225 if (rtlight->static_meshchain_shadow_zpass)
4226 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
4227 shadowzpasstris += mesh->numtriangles;
4229 shadowzfailtris = 0;
4230 if (rtlight->static_meshchain_shadow_zfail)
4231 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
4232 shadowzfailtris += mesh->numtriangles;
4235 if (rtlight->static_numlighttrispvsbytes)
4236 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
4237 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
4241 if (rtlight->static_numshadowtrispvsbytes)
4242 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
4243 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
4246 if (developer_extra.integer)
4247 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);
4250 void R_RTLight_Uncompile(rtlight_t *rtlight)
4252 if (rtlight->compiled)
4254 if (rtlight->static_meshchain_shadow_zpass)
4255 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
4256 rtlight->static_meshchain_shadow_zpass = NULL;
4257 if (rtlight->static_meshchain_shadow_zfail)
4258 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
4259 rtlight->static_meshchain_shadow_zfail = NULL;
4260 if (rtlight->static_meshchain_shadow_shadowmap)
4261 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
4262 rtlight->static_meshchain_shadow_shadowmap = NULL;
4263 // these allocations are grouped
4264 if (rtlight->static_surfacelist)
4265 Mem_Free(rtlight->static_surfacelist);
4266 rtlight->static_numleafs = 0;
4267 rtlight->static_numleafpvsbytes = 0;
4268 rtlight->static_leaflist = NULL;
4269 rtlight->static_leafpvs = NULL;
4270 rtlight->static_numsurfaces = 0;
4271 rtlight->static_surfacelist = NULL;
4272 rtlight->static_numshadowtrispvsbytes = 0;
4273 rtlight->static_shadowtrispvs = NULL;
4274 rtlight->static_numlighttrispvsbytes = 0;
4275 rtlight->static_lighttrispvs = NULL;
4276 rtlight->compiled = false;
4280 void R_Shadow_UncompileWorldLights(void)
4284 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4285 for (lightindex = 0;lightindex < range;lightindex++)
4287 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4290 R_RTLight_Uncompile(&light->rtlight);
4294 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
4298 // reset the count of frustum planes
4299 // see rtlight->cached_frustumplanes definition for how much this array
4301 rtlight->cached_numfrustumplanes = 0;
4303 if (r_trippy.integer)
4306 // haven't implemented a culling path for ortho rendering
4307 if (!r_refdef.view.useperspective)
4309 // check if the light is on screen and copy the 4 planes if it is
4310 for (i = 0;i < 4;i++)
4311 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4314 for (i = 0;i < 4;i++)
4315 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4320 // generate a deformed frustum that includes the light origin, this is
4321 // used to cull shadow casting surfaces that can not possibly cast a
4322 // shadow onto the visible light-receiving surfaces, which can be a
4325 // if the light origin is onscreen the result will be 4 planes exactly
4326 // if the light origin is offscreen on only one axis the result will
4327 // be exactly 5 planes (split-side case)
4328 // if the light origin is offscreen on two axes the result will be
4329 // exactly 4 planes (stretched corner case)
4330 for (i = 0;i < 4;i++)
4332 // quickly reject standard frustum planes that put the light
4333 // origin outside the frustum
4334 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4337 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4339 // if all the standard frustum planes were accepted, the light is onscreen
4340 // otherwise we need to generate some more planes below...
4341 if (rtlight->cached_numfrustumplanes < 4)
4343 // at least one of the stock frustum planes failed, so we need to
4344 // create one or two custom planes to enclose the light origin
4345 for (i = 0;i < 4;i++)
4347 // create a plane using the view origin and light origin, and a
4348 // single point from the frustum corner set
4349 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
4350 VectorNormalize(plane.normal);
4351 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
4352 // see if this plane is backwards and flip it if so
4353 for (j = 0;j < 4;j++)
4354 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4358 VectorNegate(plane.normal, plane.normal);
4360 // flipped plane, test again to see if it is now valid
4361 for (j = 0;j < 4;j++)
4362 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4364 // if the plane is still not valid, then it is dividing the
4365 // frustum and has to be rejected
4369 // we have created a valid plane, compute extra info
4370 PlaneClassify(&plane);
4372 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4374 // if we've found 5 frustum planes then we have constructed a
4375 // proper split-side case and do not need to keep searching for
4376 // planes to enclose the light origin
4377 if (rtlight->cached_numfrustumplanes == 5)
4385 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
4387 plane = rtlight->cached_frustumplanes[i];
4388 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));
4393 // now add the light-space box planes if the light box is rotated, as any
4394 // caster outside the oriented light box is irrelevant (even if it passed
4395 // the worldspace light box, which is axial)
4396 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
4398 for (i = 0;i < 6;i++)
4402 v[i >> 1] = (i & 1) ? -1 : 1;
4403 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
4404 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
4405 plane.dist = VectorNormalizeLength(plane.normal);
4406 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
4407 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4413 // add the world-space reduced box planes
4414 for (i = 0;i < 6;i++)
4416 VectorClear(plane.normal);
4417 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
4418 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
4419 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4428 // reduce all plane distances to tightly fit the rtlight cull box, which
4430 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4431 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4432 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4433 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4434 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4435 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4436 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4437 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4438 oldnum = rtlight->cached_numfrustumplanes;
4439 rtlight->cached_numfrustumplanes = 0;
4440 for (j = 0;j < oldnum;j++)
4442 // find the nearest point on the box to this plane
4443 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
4444 for (i = 1;i < 8;i++)
4446 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
4447 if (bestdist > dist)
4450 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);
4451 // if the nearest point is near or behind the plane, we want this
4452 // plane, otherwise the plane is useless as it won't cull anything
4453 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
4455 PlaneClassify(&rtlight->cached_frustumplanes[j]);
4456 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
4463 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
4467 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4469 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4472 GL_CullFace(GL_NONE);
4473 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
4474 for (;mesh;mesh = mesh->next)
4476 if (!mesh->sidetotals[r_shadow_shadowmapside])
4478 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
4479 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4480 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);
4484 else if (r_refdef.scene.worldentity->model)
4485 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);
4487 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4490 static void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
4492 qboolean zpass = false;
4495 int surfacelistindex;
4496 msurface_t *surface;
4498 // if triangle neighbors are disabled, shadowvolumes are disabled
4499 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
4502 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4504 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4507 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
4509 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
4510 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
4512 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
4513 for (;mesh;mesh = mesh->next)
4515 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->numtriangles;
4516 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4517 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
4519 // increment stencil if frontface is infront of depthbuffer
4520 GL_CullFace(r_refdef.view.cullface_back);
4521 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
4522 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);
4523 // decrement stencil if backface is infront of depthbuffer
4524 GL_CullFace(r_refdef.view.cullface_front);
4525 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
4527 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
4529 // decrement stencil if backface is behind depthbuffer
4530 GL_CullFace(r_refdef.view.cullface_front);
4531 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
4532 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);
4533 // increment stencil if frontface is behind depthbuffer
4534 GL_CullFace(r_refdef.view.cullface_back);
4535 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
4537 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);
4541 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
4543 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
4544 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
4545 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
4547 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
4548 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
4549 if (CHECKPVSBIT(trispvs, t))
4550 shadowmarklist[numshadowmark++] = t;
4552 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);
4554 else if (numsurfaces)
4556 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);
4559 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4562 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
4564 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
4565 vec_t relativeshadowradius;
4566 RSurf_ActiveModelEntity(ent, false, false, false);
4567 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
4568 // we need to re-init the shader for each entity because the matrix changed
4569 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
4570 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
4571 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
4572 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
4573 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
4574 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
4575 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
4576 switch (r_shadow_rendermode)
4578 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
4579 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4582 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4585 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4588 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
4590 // set up properties for rendering light onto this entity
4591 RSurf_ActiveModelEntity(ent, true, true, false);
4592 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
4593 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4594 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4595 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4598 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
4600 if (!r_refdef.scene.worldmodel->DrawLight)
4603 // set up properties for rendering light onto this entity
4604 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4605 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
4606 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4607 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4608 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4610 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
4612 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4615 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
4617 dp_model_t *model = ent->model;
4618 if (!model->DrawLight)
4621 R_Shadow_SetupEntityLight(ent);
4623 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
4625 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4628 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
4632 int numleafs, numsurfaces;
4633 int *leaflist, *surfacelist;
4634 unsigned char *leafpvs;
4635 unsigned char *shadowtrispvs;
4636 unsigned char *lighttrispvs;
4637 //unsigned char *surfacesides;
4638 int numlightentities;
4639 int numlightentities_noselfshadow;
4640 int numshadowentities;
4641 int numshadowentities_noselfshadow;
4642 // FIXME: bounds check lightentities and shadowentities, etc.
4643 static entity_render_t *lightentities[MAX_EDICTS];
4644 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
4645 static entity_render_t *shadowentities[MAX_EDICTS];
4646 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
4648 qboolean castshadows;
4650 rtlight->draw = false;
4651 rtlight->cached_numlightentities = 0;
4652 rtlight->cached_numlightentities_noselfshadow = 0;
4653 rtlight->cached_numshadowentities = 0;
4654 rtlight->cached_numshadowentities_noselfshadow = 0;
4655 rtlight->cached_numsurfaces = 0;
4656 rtlight->cached_lightentities = NULL;
4657 rtlight->cached_lightentities_noselfshadow = NULL;
4658 rtlight->cached_shadowentities = NULL;
4659 rtlight->cached_shadowentities_noselfshadow = NULL;
4660 rtlight->cached_shadowtrispvs = NULL;
4661 rtlight->cached_lighttrispvs = NULL;
4662 rtlight->cached_surfacelist = NULL;
4663 rtlight->shadowmapsidesize = 0;
4665 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
4666 // skip lights that are basically invisible (color 0 0 0)
4667 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
4669 // loading is done before visibility checks because loading should happen
4670 // all at once at the start of a level, not when it stalls gameplay.
4671 // (especially important to benchmarks)
4673 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
4675 if (rtlight->compiled)
4676 R_RTLight_Uncompile(rtlight);
4677 R_RTLight_Compile(rtlight);
4681 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
4683 // look up the light style value at this time
4684 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4685 VectorScale(rtlight->color, f, rtlight->currentcolor);
4687 if (rtlight->selected)
4689 f = 2 + sin(realtime * M_PI * 4.0);
4690 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
4694 // skip if lightstyle is currently off
4695 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
4698 // skip processing on corona-only lights
4702 // skip if the light box is not touching any visible leafs
4703 if (r_shadow_culllights_pvs.integer
4704 && r_refdef.scene.worldmodel
4705 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
4706 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, rtlight->cullmins, rtlight->cullmaxs))
4709 // skip if the light box is not visible to traceline
4710 if (r_shadow_culllights_trace.integer)
4712 if (rtlight->trace_timer != realtime && R_CanSeeBox(rtlight->trace_timer == 0 ? r_shadow_culllights_trace_tempsamples.integer : r_shadow_culllights_trace_samples.integer, r_shadow_culllights_trace_eyejitter.value, r_shadow_culllights_trace_enlarge.value, r_refdef.view.origin, rtlight->cullmins, rtlight->cullmaxs))
4713 rtlight->trace_timer = realtime;
4714 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
4718 // skip if the light box is off screen
4719 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
4722 // in the typical case this will be quickly replaced by GetLightInfo
4723 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
4724 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
4726 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4728 // 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
4729 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
4732 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
4734 // compiled light, world available and can receive realtime lighting
4735 // retrieve leaf information
4736 numleafs = rtlight->static_numleafs;
4737 leaflist = rtlight->static_leaflist;
4738 leafpvs = rtlight->static_leafpvs;
4739 numsurfaces = rtlight->static_numsurfaces;
4740 surfacelist = rtlight->static_surfacelist;
4741 //surfacesides = NULL;
4742 shadowtrispvs = rtlight->static_shadowtrispvs;
4743 lighttrispvs = rtlight->static_lighttrispvs;
4745 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4747 // dynamic light, world available and can receive realtime lighting
4748 // calculate lit surfaces and leafs
4749 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, rtlight->shadow == 0);
4750 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4751 leaflist = r_shadow_buffer_leaflist;
4752 leafpvs = r_shadow_buffer_leafpvs;
4753 surfacelist = r_shadow_buffer_surfacelist;
4754 //surfacesides = r_shadow_buffer_surfacesides;
4755 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4756 lighttrispvs = r_shadow_buffer_lighttrispvs;
4757 // if the reduced leaf bounds are offscreen, skip it
4758 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4769 //surfacesides = NULL;
4770 shadowtrispvs = NULL;
4771 lighttrispvs = NULL;
4773 // check if light is illuminating any visible leafs
4776 for (i = 0; i < numleafs; i++)
4777 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4783 // make a list of lit entities and shadow casting entities
4784 numlightentities = 0;
4785 numlightentities_noselfshadow = 0;
4786 numshadowentities = 0;
4787 numshadowentities_noselfshadow = 0;
4789 // add dynamic entities that are lit by the light
4790 for (i = 0; i < r_refdef.scene.numentities; i++)
4793 entity_render_t *ent = r_refdef.scene.entities[i];
4795 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4797 // skip the object entirely if it is not within the valid
4798 // shadow-casting region (which includes the lit region)
4799 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
4801 if (!(model = ent->model))
4803 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4805 // this entity wants to receive light, is visible, and is
4806 // inside the light box
4807 // TODO: check if the surfaces in the model can receive light
4808 // so now check if it's in a leaf seen by the light
4809 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))
4811 if (ent->flags & RENDER_NOSELFSHADOW)
4812 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
4814 lightentities[numlightentities++] = ent;
4815 // since it is lit, it probably also casts a shadow...
4816 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4817 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4818 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4820 // note: exterior models without the RENDER_NOSELFSHADOW
4821 // flag still create a RENDER_NOSELFSHADOW shadow but
4822 // are lit normally, this means that they are
4823 // self-shadowing but do not shadow other
4824 // RENDER_NOSELFSHADOW entities such as the gun
4825 // (very weird, but keeps the player shadow off the gun)
4826 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4827 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4829 shadowentities[numshadowentities++] = ent;
4832 else if (ent->flags & RENDER_SHADOW)
4834 // this entity is not receiving light, but may still need to
4836 // TODO: check if the surfaces in the model can cast shadow
4837 // now check if it is in a leaf seen by the light
4838 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))
4840 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4841 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4842 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4844 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4845 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4847 shadowentities[numshadowentities++] = ent;
4852 // return if there's nothing at all to light
4853 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4856 // count this light in the r_speeds
4857 r_refdef.stats[r_stat_lights]++;
4859 // flag it as worth drawing later
4860 rtlight->draw = true;
4862 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
4863 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4865 numshadowentities = numshadowentities_noselfshadow = 0;
4866 rtlight->castshadows = castshadows;
4868 // cache all the animated entities that cast a shadow but are not visible
4869 for (i = 0; i < numshadowentities; i++)
4870 R_AnimCache_GetEntity(shadowentities[i], false, false);
4871 for (i = 0; i < numshadowentities_noselfshadow; i++)
4872 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4874 // 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)
4875 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
4877 for (i = 0; i < numshadowentities_noselfshadow; i++)
4878 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
4879 numshadowentities_noselfshadow = 0;
4882 // we can convert noselfshadow to regular if there are no casters of that type
4883 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
4885 for (i = 0; i < numlightentities_noselfshadow; i++)
4886 lightentities[numlightentities++] = lightentities_noselfshadow[i];
4887 numlightentities_noselfshadow = 0;
4890 // allocate some temporary memory for rendering this light later in the frame
4891 // reusable buffers need to be copied, static data can be used as-is
4892 rtlight->cached_numlightentities = numlightentities;
4893 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
4894 rtlight->cached_numshadowentities = numshadowentities;
4895 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4896 rtlight->cached_numsurfaces = numsurfaces;
4897 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4898 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4899 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4900 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4901 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4903 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4904 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4905 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4906 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4907 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4911 // compiled light data
4912 rtlight->cached_shadowtrispvs = shadowtrispvs;
4913 rtlight->cached_lighttrispvs = lighttrispvs;
4914 rtlight->cached_surfacelist = surfacelist;
4917 if (R_Shadow_ShadowMappingEnabled())
4919 // figure out the shadowmapping parameters for this light
4920 vec3_t nearestpoint;
4923 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4924 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4925 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4926 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4927 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
4928 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4929 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4930 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4931 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
4935 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
4939 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4940 int numlightentities;
4941 int numlightentities_noselfshadow;
4942 int numshadowentities;
4943 int numshadowentities_noselfshadow;
4944 entity_render_t **lightentities;
4945 entity_render_t **lightentities_noselfshadow;
4946 entity_render_t **shadowentities;
4947 entity_render_t **shadowentities_noselfshadow;
4949 static unsigned char entitysides[MAX_EDICTS];
4950 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4956 matrix4x4_t radiustolight;
4958 // check if we cached this light this frame (meaning it is worth drawing)
4959 if (!rtlight->draw || !rtlight->castshadows)
4962 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
4963 if (rtlight->shadowmapatlassidesize == 0)
4965 rtlight->castshadows = false;
4969 // set up a scissor rectangle for this light
4970 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4973 // don't let sound skip if going slow
4974 if (r_refdef.scene.extraupdate)
4977 numlightentities = rtlight->cached_numlightentities;
4978 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4979 numshadowentities = rtlight->cached_numshadowentities;
4980 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4981 numsurfaces = rtlight->cached_numsurfaces;
4982 lightentities = rtlight->cached_lightentities;
4983 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4984 shadowentities = rtlight->cached_shadowentities;
4985 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4986 shadowtrispvs = rtlight->cached_shadowtrispvs;
4987 lighttrispvs = rtlight->cached_lighttrispvs;
4988 surfacelist = rtlight->cached_surfacelist;
4990 // make this the active rtlight for rendering purposes
4991 R_Shadow_RenderMode_ActiveLight(rtlight);
4993 radiustolight = rtlight->matrix_worldtolight;
4994 Matrix4x4_Abs(&radiustolight);
4996 size = rtlight->shadowmapatlassidesize;
4997 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4999 surfacesides = NULL;
5004 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
5006 castermask = rtlight->static_shadowmap_casters;
5007 receivermask = rtlight->static_shadowmap_receivers;
5011 surfacesides = r_shadow_buffer_surfacesides;
5012 for (i = 0; i < numsurfaces; i++)
5014 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
5015 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
5016 castermask |= surfacesides[i];
5017 receivermask |= surfacesides[i];
5022 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
5023 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
5024 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
5025 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
5027 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
5031 for (i = 0; i < numshadowentities; i++)
5032 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
5033 for (i = 0; i < numshadowentities_noselfshadow; i++)
5034 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
5037 // there is no need to render shadows for sides that have no receivers...
5038 castermask &= receivermask;
5040 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
5042 // render shadow casters into shadowmaps for this light
5043 for (side = 0; side < 6; side++)
5045 int bit = 1 << side;
5046 if (castermask & bit)
5048 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
5050 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
5051 for (i = 0; i < numshadowentities; i++)
5052 if (entitysides[i] & bit)
5053 R_Shadow_DrawEntityShadow(shadowentities[i]);
5054 for (i = 0; i < numshadowentities_noselfshadow; i++)
5055 if (entitysides_noselfshadow[i] & bit)
5056 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5059 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
5060 if (numshadowentities_noselfshadow)
5062 for (side = 0; side < 6; side++)
5064 int bit = 1 << side;
5065 if (castermask & bit)
5067 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
5069 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
5070 for (i = 0; i < numshadowentities; i++)
5071 if (entitysides[i] & bit)
5072 R_Shadow_DrawEntityShadow(shadowentities[i]);
5078 static void R_Shadow_DrawLight(rtlight_t *rtlight)
5082 unsigned char *shadowtrispvs, *lighttrispvs;
5083 int numlightentities;
5084 int numlightentities_noselfshadow;
5085 int numshadowentities;
5086 int numshadowentities_noselfshadow;
5087 entity_render_t **lightentities;
5088 entity_render_t **lightentities_noselfshadow;
5089 entity_render_t **shadowentities;
5090 entity_render_t **shadowentities_noselfshadow;
5092 qboolean castshadows;
5094 // check if we cached this light this frame (meaning it is worth drawing)
5098 // set up a scissor rectangle for this light
5099 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
5102 // don't let sound skip if going slow
5103 if (r_refdef.scene.extraupdate)
5106 numlightentities = rtlight->cached_numlightentities;
5107 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
5108 numshadowentities = rtlight->cached_numshadowentities;
5109 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
5110 numsurfaces = rtlight->cached_numsurfaces;
5111 lightentities = rtlight->cached_lightentities;
5112 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
5113 shadowentities = rtlight->cached_shadowentities;
5114 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
5115 shadowtrispvs = rtlight->cached_shadowtrispvs;
5116 lighttrispvs = rtlight->cached_lighttrispvs;
5117 surfacelist = rtlight->cached_surfacelist;
5118 castshadows = rtlight->castshadows;
5120 // make this the active rtlight for rendering purposes
5121 R_Shadow_RenderMode_ActiveLight(rtlight);
5123 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
5125 // optionally draw visible shape of the shadow volumes
5126 // for performance analysis by level designers
5127 R_Shadow_RenderMode_VisibleShadowVolumes();
5129 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
5130 for (i = 0;i < numshadowentities;i++)
5131 R_Shadow_DrawEntityShadow(shadowentities[i]);
5132 for (i = 0;i < numshadowentities_noselfshadow;i++)
5133 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5134 R_Shadow_RenderMode_VisibleLighting(false, false);
5137 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
5139 // optionally draw the illuminated areas
5140 // for performance analysis by level designers
5141 R_Shadow_RenderMode_VisibleLighting(false, false);
5143 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5144 for (i = 0;i < numlightentities;i++)
5145 R_Shadow_DrawEntityLight(lightentities[i]);
5146 for (i = 0;i < numlightentities_noselfshadow;i++)
5147 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5150 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
5154 float shadowmapoffsetnoselfshadow = 0;
5155 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
5156 Matrix4x4_Abs(&radiustolight);
5158 size = rtlight->shadowmapatlassidesize;
5159 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
5161 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
5163 if (rtlight->cached_numshadowentities_noselfshadow)
5164 shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
5166 // render lighting using the depth texture as shadowmap
5167 // draw lighting in the unmasked areas
5168 if (numsurfaces + numlightentities)
5170 R_Shadow_RenderMode_Lighting(false, false, true, false);
5171 // draw lighting in the unmasked areas
5173 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5174 for (i = 0; i < numlightentities; i++)
5175 R_Shadow_DrawEntityLight(lightentities[i]);
5177 // offset to the noselfshadow part of the atlas and draw those too
5178 if (numlightentities_noselfshadow)
5180 R_Shadow_RenderMode_Lighting(false, false, true, true);
5181 for (i = 0; i < numlightentities_noselfshadow; i++)
5182 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5185 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5186 if (r_shadow_usingdeferredprepass)
5187 R_Shadow_RenderMode_DrawDeferredLight(true);
5189 else if (castshadows && vid.stencil)
5191 // draw stencil shadow volumes to mask off pixels that are in shadow
5192 // so that they won't receive lighting
5193 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
5194 R_Shadow_ClearStencil();
5197 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
5198 for (i = 0;i < numshadowentities;i++)
5199 R_Shadow_DrawEntityShadow(shadowentities[i]);
5201 // draw lighting in the unmasked areas
5202 R_Shadow_RenderMode_Lighting(true, false, false, false);
5203 for (i = 0;i < numlightentities_noselfshadow;i++)
5204 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5206 for (i = 0;i < numshadowentities_noselfshadow;i++)
5207 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5209 // draw lighting in the unmasked areas
5210 R_Shadow_RenderMode_Lighting(true, false, false, false);
5212 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5213 for (i = 0;i < numlightentities;i++)
5214 R_Shadow_DrawEntityLight(lightentities[i]);
5216 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5217 if (r_shadow_usingdeferredprepass)
5218 R_Shadow_RenderMode_DrawDeferredLight(false);
5222 // draw lighting in the unmasked areas
5223 R_Shadow_RenderMode_Lighting(false, false, false, false);
5225 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5226 for (i = 0;i < numlightentities;i++)
5227 R_Shadow_DrawEntityLight(lightentities[i]);
5228 for (i = 0;i < numlightentities_noselfshadow;i++)
5229 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5231 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5232 if (r_shadow_usingdeferredprepass)
5233 R_Shadow_RenderMode_DrawDeferredLight(false);
5237 static void R_Shadow_FreeDeferred(void)
5239 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
5240 r_shadow_prepassgeometryfbo = 0;
5242 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
5243 r_shadow_prepasslightingdiffusespecularfbo = 0;
5245 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
5246 r_shadow_prepasslightingdiffusefbo = 0;
5248 if (r_shadow_prepassgeometrydepthbuffer)
5249 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
5250 r_shadow_prepassgeometrydepthbuffer = NULL;
5252 if (r_shadow_prepassgeometrynormalmaptexture)
5253 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
5254 r_shadow_prepassgeometrynormalmaptexture = NULL;
5256 if (r_shadow_prepasslightingdiffusetexture)
5257 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
5258 r_shadow_prepasslightingdiffusetexture = NULL;
5260 if (r_shadow_prepasslightingspeculartexture)
5261 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
5262 r_shadow_prepasslightingspeculartexture = NULL;
5265 void R_Shadow_DrawPrepass(void)
5269 entity_render_t *ent;
5270 float clearcolor[4];
5272 R_Mesh_ResetTextureState();
5274 GL_ColorMask(1,1,1,1);
5275 GL_BlendFunc(GL_ONE, GL_ZERO);
5278 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5279 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
5280 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
5281 if (r_timereport_active)
5282 R_TimeReport("prepasscleargeom");
5284 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
5285 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
5286 if (r_timereport_active)
5287 R_TimeReport("prepassworld");
5289 for (i = 0;i < r_refdef.scene.numentities;i++)
5291 if (!r_refdef.viewcache.entityvisible[i])
5293 ent = r_refdef.scene.entities[i];
5294 if (ent->model && ent->model->DrawPrepass != NULL)
5295 ent->model->DrawPrepass(ent);
5298 if (r_timereport_active)
5299 R_TimeReport("prepassmodels");
5301 GL_DepthMask(false);
5302 GL_ColorMask(1,1,1,1);
5305 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5306 Vector4Set(clearcolor, 0, 0, 0, 0);
5307 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
5308 if (r_timereport_active)
5309 R_TimeReport("prepassclearlit");
5311 R_Shadow_RenderMode_Begin();
5313 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5314 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5316 R_Shadow_RenderMode_End();
5318 if (r_timereport_active)
5319 R_TimeReport("prepasslights");
5322 #define MAX_SCENELIGHTS 65536
5323 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
5325 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
5327 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
5329 r_shadow_scenemaxlights *= 2;
5330 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
5331 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
5333 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
5337 void R_Shadow_DrawLightSprites(void);
5338 void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
5347 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
5348 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
5349 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
5351 if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
5352 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
5353 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
5354 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
5355 r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) ||
5356 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
5357 r_shadow_shadowmapborder != shadowmapborder ||
5358 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
5359 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
5360 R_Shadow_FreeShadowMaps();
5362 r_shadow_fb_fbo = fbo;
5363 r_shadow_fb_depthtexture = depthtexture;
5364 r_shadow_fb_colortexture = colortexture;
5366 r_shadow_usingshadowmaportho = false;
5368 switch (vid.renderpath)
5370 case RENDERPATH_GL20:
5371 case RENDERPATH_D3D9:
5372 case RENDERPATH_D3D10:
5373 case RENDERPATH_D3D11:
5374 case RENDERPATH_SOFT:
5376 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
5378 r_shadow_usingdeferredprepass = false;
5379 if (r_shadow_prepass_width)
5380 R_Shadow_FreeDeferred();
5381 r_shadow_prepass_width = r_shadow_prepass_height = 0;
5385 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
5387 R_Shadow_FreeDeferred();
5389 r_shadow_usingdeferredprepass = true;
5390 r_shadow_prepass_width = vid.width;
5391 r_shadow_prepass_height = vid.height;
5392 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
5393 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);
5394 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);
5395 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);
5397 // set up the geometry pass fbo (depth + normalmap)
5398 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5399 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5400 // render depth into a renderbuffer and other important properties into the normalmap texture
5402 // set up the lighting pass fbo (diffuse + specular)
5403 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5404 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5405 // render diffuse into one texture and specular into another,
5406 // with depth and normalmap bound as textures,
5407 // with depth bound as attachment as well
5409 // set up the lighting pass fbo (diffuse)
5410 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5411 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5412 // render diffuse into one texture,
5413 // with depth and normalmap bound as textures,
5414 // with depth bound as attachment as well
5418 case RENDERPATH_GL11:
5419 case RENDERPATH_GL13:
5420 case RENDERPATH_GLES1:
5421 case RENDERPATH_GLES2:
5422 r_shadow_usingdeferredprepass = false;
5426 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);
5428 r_shadow_scenenumlights = 0;
5429 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5430 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5431 for (lightindex = 0; lightindex < range; lightindex++)
5433 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5434 if (light && (light->flags & flag))
5436 R_Shadow_PrepareLight(&light->rtlight);
5437 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5440 if (r_refdef.scene.rtdlight)
5442 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5444 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
5445 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
5448 else if (gl_flashblend.integer)
5450 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5452 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
5453 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
5454 VectorScale(rtlight->color, f, rtlight->currentcolor);
5458 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
5459 if (r_shadow_debuglight.integer >= 0)
5461 r_shadow_scenenumlights = 0;
5462 lightindex = r_shadow_debuglight.integer;
5463 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5466 R_Shadow_PrepareLight(&light->rtlight);
5467 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5471 // if we're doing shadowmaps we need to prepare the atlas layout now
5472 if (R_Shadow_ShadowMappingEnabled())
5476 // allocate shadowmaps in the atlas now
5477 // 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...
5478 for (lod = 0; lod < 16; lod++)
5480 int packing_success = 0;
5481 int packing_failure = 0;
5482 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
5483 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
5484 if (r_shadow_shadowmapatlas_modelshadows_size)
5485 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);
5486 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5488 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
5489 int size = rtlight->shadowmapsidesize >> lod;
5491 if (!rtlight->castshadows)
5493 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
5496 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
5497 if (rtlight->cached_numshadowentities_noselfshadow)
5499 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
5501 rtlight->shadowmapatlassidesize = size;
5506 // note down that we failed to pack this one, it will have to disable shadows
5507 rtlight->shadowmapatlassidesize = 0;
5511 // generally everything fits and we stop here on the first iteration
5512 if (packing_failure == 0)
5517 if (r_editlights.integer)
5518 R_Shadow_DrawLightSprites();
5521 void R_Shadow_DrawShadowMaps(void)
5523 R_Shadow_RenderMode_Begin();
5524 R_Shadow_RenderMode_ActiveLight(NULL);
5526 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
5527 R_Shadow_ClearShadowMapTexture();
5529 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
5530 if (r_shadow_shadowmapatlas_modelshadows_size)
5532 R_Shadow_DrawModelShadowMaps();
5533 // don't let sound skip if going slow
5534 if (r_refdef.scene.extraupdate)
5538 if (R_Shadow_ShadowMappingEnabled())
5541 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5542 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
5545 R_Shadow_RenderMode_End();
5548 void R_Shadow_DrawLights(void)
5552 R_Shadow_RenderMode_Begin();
5554 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5555 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5557 R_Shadow_RenderMode_End();
5560 #define MAX_MODELSHADOWS 1024
5561 static int r_shadow_nummodelshadows;
5562 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
5564 void R_Shadow_PrepareModelShadows(void)
5567 float scale, size, radius, dot1, dot2;
5568 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5569 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
5570 entity_render_t *ent;
5572 r_shadow_nummodelshadows = 0;
5573 r_shadow_shadowmapatlas_modelshadows_size = 0;
5575 if (!r_refdef.scene.numentities || r_refdef.scene.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
5578 switch (r_shadow_shadowmode)
5580 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
5581 if (r_shadows.integer >= 2)
5584 case R_SHADOW_SHADOWMODE_STENCIL:
5587 for (i = 0; i < r_refdef.scene.numentities; i++)
5589 ent = r_refdef.scene.entities[i];
5590 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5592 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5594 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5595 R_AnimCache_GetEntity(ent, false, false);
5603 size = r_shadow_shadowmaptexturesize / 4;
5604 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
5605 radius = 0.5f * size / scale;
5607 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5608 VectorCopy(prvmshadowdir, shadowdir);
5609 VectorNormalize(shadowdir);
5610 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5611 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5612 if (fabs(dot1) <= fabs(dot2))
5613 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5615 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5616 VectorNormalize(shadowforward);
5617 CrossProduct(shadowdir, shadowforward, shadowright);
5618 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5619 VectorCopy(prvmshadowfocus, shadowfocus);
5620 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5621 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5622 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5623 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5624 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5626 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5628 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5629 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5630 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5631 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5632 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5633 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5635 for (i = 0; i < r_refdef.scene.numentities; i++)
5637 ent = r_refdef.scene.entities[i];
5638 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
5640 // cast shadows from anything of the map (submodels are optional)
5641 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5643 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5645 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5646 R_AnimCache_GetEntity(ent, false, false);
5650 if (r_shadow_nummodelshadows)
5652 r_shadow_shadowmapatlas_modelshadows_x = 0;
5653 r_shadow_shadowmapatlas_modelshadows_y = 0;
5654 r_shadow_shadowmapatlas_modelshadows_size = size;
5658 static void R_Shadow_DrawModelShadowMaps(void)
5661 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
5662 entity_render_t *ent;
5663 vec3_t relativelightorigin;
5664 vec3_t relativelightdirection, relativeforward, relativeright;
5665 vec3_t relativeshadowmins, relativeshadowmaxs;
5666 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
5667 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5669 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
5670 r_viewport_t viewport;
5672 size = r_shadow_shadowmapatlas_modelshadows_size;
5673 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
5674 radius = 0.5f / scale;
5675 nearclip = -r_shadows_throwdistance.value;
5676 farclip = r_shadows_throwdistance.value;
5677 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);
5679 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
5680 r_shadow_modelshadowmap_parameters[0] = size;
5681 r_shadow_modelshadowmap_parameters[1] = size;
5682 r_shadow_modelshadowmap_parameters[2] = 1.0;
5683 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
5684 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
5685 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
5686 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
5687 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
5688 r_shadow_usingshadowmaportho = true;
5690 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5691 VectorCopy(prvmshadowdir, shadowdir);
5692 VectorNormalize(shadowdir);
5693 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5694 VectorCopy(prvmshadowfocus, shadowfocus);
5695 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5696 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5697 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5698 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5699 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5700 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5701 if (fabs(dot1) <= fabs(dot2))
5702 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5704 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5705 VectorNormalize(shadowforward);
5706 VectorM(scale, shadowforward, &m[0]);
5707 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5709 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
5710 CrossProduct(shadowdir, shadowforward, shadowright);
5711 VectorM(scale, shadowright, &m[4]);
5712 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
5713 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
5714 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
5715 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
5716 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
5717 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);
5718 R_SetViewport(&viewport);
5720 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5722 // render into a slightly restricted region so that the borders of the
5723 // shadowmap area fade away, rather than streaking across everything
5724 // outside the usable area
5725 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
5727 for (i = 0;i < r_shadow_nummodelshadows;i++)
5729 ent = r_shadow_modelshadows[i];
5730 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5731 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
5732 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5733 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
5734 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
5735 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5736 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5737 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5738 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5739 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5740 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5741 RSurf_ActiveModelEntity(ent, false, false, false);
5742 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
5743 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5749 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
5751 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
5753 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
5754 Cvar_SetValueQuick(&r_test, 0);
5759 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
5760 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
5761 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
5762 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
5763 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
5764 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
5766 switch (vid.renderpath)
5768 case RENDERPATH_GL11:
5769 case RENDERPATH_GL13:
5770 case RENDERPATH_GL20:
5771 case RENDERPATH_SOFT:
5772 case RENDERPATH_GLES1:
5773 case RENDERPATH_GLES2:
5775 case RENDERPATH_D3D9:
5776 case RENDERPATH_D3D10:
5777 case RENDERPATH_D3D11:
5778 #ifdef MATRIX4x4_OPENGLORIENTATION
5779 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5780 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
5781 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
5782 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
5784 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5785 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
5786 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
5787 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
5793 void R_Shadow_DrawModelShadows(void)
5796 float relativethrowdistance;
5797 entity_render_t *ent;
5798 vec3_t relativelightorigin;
5799 vec3_t relativelightdirection;
5800 vec3_t relativeshadowmins, relativeshadowmaxs;
5801 vec3_t tmp, shadowdir;
5802 prvm_vec3_t prvmshadowdir;
5804 if (!r_shadow_nummodelshadows || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
5807 R_ResetViewRendering3D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5808 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
5809 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5810 R_Shadow_RenderMode_Begin();
5811 R_Shadow_RenderMode_ActiveLight(NULL);
5812 r_shadow_lightscissor[0] = r_refdef.view.x;
5813 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
5814 r_shadow_lightscissor[2] = r_refdef.view.width;
5815 r_shadow_lightscissor[3] = r_refdef.view.height;
5816 R_Shadow_RenderMode_StencilShadowVolumes(false);
5819 if (r_shadows.integer == 2)
5821 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5822 VectorCopy(prvmshadowdir, shadowdir);
5823 VectorNormalize(shadowdir);
5826 R_Shadow_ClearStencil();
5828 for (i = 0;i < r_shadow_nummodelshadows;i++)
5830 ent = r_shadow_modelshadows[i];
5832 // cast shadows from anything of the map (submodels are optional)
5833 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5834 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
5835 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
5836 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
5837 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5840 VectorNegate(ent->render_modellight_lightdir, tmp);
5841 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
5844 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
5845 RSurf_ActiveModelEntity(ent, false, false, false);
5846 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
5847 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5850 // not really the right mode, but this will disable any silly stencil features
5851 R_Shadow_RenderMode_End();
5853 // set up ortho view for rendering this pass
5854 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5855 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5856 //GL_ScissorTest(true);
5857 //R_EntityMatrix(&identitymatrix);
5858 //R_Mesh_ResetTextureState();
5859 R_ResetViewRendering2D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5861 // set up a darkening blend on shadowed areas
5862 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5863 //GL_DepthRange(0, 1);
5864 //GL_DepthTest(false);
5865 //GL_DepthMask(false);
5866 //GL_PolygonOffset(0, 0);CHECKGLERROR
5867 GL_Color(0, 0, 0, r_shadows_darken.value);
5868 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5869 //GL_DepthFunc(GL_ALWAYS);
5870 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5872 // apply the blend to the shadowed areas
5873 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5874 R_SetupShader_Generic_NoTexture(false, true);
5875 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5877 // restore the viewport
5878 R_SetViewport(&r_refdef.view.viewport);
5880 // restore other state to normal
5881 //R_Shadow_RenderMode_End();
5884 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5887 vec3_t centerorigin;
5888 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5891 // if it's too close, skip it
5892 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5894 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5897 if (usequery && r_numqueries + 2 <= r_maxqueries)
5899 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5900 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5901 // 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
5902 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5904 switch(vid.renderpath)
5906 case RENDERPATH_GL11:
5907 case RENDERPATH_GL13:
5908 case RENDERPATH_GL20:
5909 case RENDERPATH_GLES1:
5910 case RENDERPATH_GLES2:
5911 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5913 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5914 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5915 GL_DepthFunc(GL_ALWAYS);
5916 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5917 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5918 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5919 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5920 GL_DepthFunc(GL_LEQUAL);
5921 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5922 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5923 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5924 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5925 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5929 case RENDERPATH_D3D9:
5930 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5932 case RENDERPATH_D3D10:
5933 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5935 case RENDERPATH_D3D11:
5936 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5938 case RENDERPATH_SOFT:
5939 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5943 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5946 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5948 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5951 unsigned int occlude = 0;
5952 GLint allpixels = 0, visiblepixels = 0;
5954 // now we have to check the query result
5955 if (rtlight->corona_queryindex_visiblepixels)
5957 switch(vid.renderpath)
5959 case RENDERPATH_GL20:
5960 case RENDERPATH_GLES1:
5961 case RENDERPATH_GLES2:
5962 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5963 // See if we can use the GPU-side method to prevent implicit sync
5964 if (vid.support.arb_query_buffer_object) {
5965 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
5966 if (!r_shadow_occlusion_buf) {
5967 qglGenBuffersARB(1, &r_shadow_occlusion_buf);
5968 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5969 qglBufferDataARB(GL_QUERY_BUFFER_ARB, 8, NULL, GL_DYNAMIC_COPY);
5971 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5973 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(0));
5974 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4));
5975 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
5976 occlude = MATERIALFLAG_OCCLUDE;
5977 cscale *= rtlight->corona_visibility;
5985 case RENDERPATH_GL11:
5986 case RENDERPATH_GL13:
5987 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5989 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5990 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5991 if (visiblepixels < 1 || allpixels < 1)
5993 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5994 cscale *= rtlight->corona_visibility;
6000 case RENDERPATH_D3D9:
6001 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6003 case RENDERPATH_D3D10:
6004 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6006 case RENDERPATH_D3D11:
6007 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6009 case RENDERPATH_SOFT:
6010 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6018 if (CL_Cache_TraceLineSurfaces(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT).fraction < 1)
6021 VectorScale(rtlight->currentcolor, cscale, color);
6022 if (VectorLength(color) > (1.0f / 256.0f))
6025 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
6028 VectorNegate(color, color);
6029 GL_BlendEquationSubtract(true);
6031 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
6032 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);
6033 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
6035 GL_BlendEquationSubtract(false);
6039 void R_Shadow_DrawCoronas(void)
6042 qboolean usequery = false;
6047 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
6049 if (r_fb.water.renderingscene)
6051 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6052 R_EntityMatrix(&identitymatrix);
6054 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6056 // check occlusion of coronas
6057 // use GL_ARB_occlusion_query if available
6058 // otherwise use raytraces
6060 switch (vid.renderpath)
6062 case RENDERPATH_GL11:
6063 case RENDERPATH_GL13:
6064 case RENDERPATH_GL20:
6065 case RENDERPATH_GLES1:
6066 case RENDERPATH_GLES2:
6067 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
6068 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
6071 GL_ColorMask(0,0,0,0);
6072 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
6073 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
6076 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
6077 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
6079 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
6082 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6083 GL_BlendFunc(GL_ONE, GL_ZERO);
6084 GL_CullFace(GL_NONE);
6085 GL_DepthMask(false);
6086 GL_DepthRange(0, 1);
6087 GL_PolygonOffset(0, 0);
6089 R_Mesh_ResetTextureState();
6090 R_SetupShader_Generic_NoTexture(false, false);
6094 case RENDERPATH_D3D9:
6096 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6098 case RENDERPATH_D3D10:
6099 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6101 case RENDERPATH_D3D11:
6102 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6104 case RENDERPATH_SOFT:
6106 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6109 for (lightindex = 0;lightindex < range;lightindex++)
6111 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6114 rtlight = &light->rtlight;
6115 rtlight->corona_visibility = 0;
6116 rtlight->corona_queryindex_visiblepixels = 0;
6117 rtlight->corona_queryindex_allpixels = 0;
6118 if (!(rtlight->flags & flag))
6120 if (rtlight->corona <= 0)
6122 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
6124 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6126 for (i = 0;i < r_refdef.scene.numlights;i++)
6128 rtlight = r_refdef.scene.lights[i];
6129 rtlight->corona_visibility = 0;
6130 rtlight->corona_queryindex_visiblepixels = 0;
6131 rtlight->corona_queryindex_allpixels = 0;
6132 if (!(rtlight->flags & flag))
6134 if (rtlight->corona <= 0)
6136 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6139 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
6141 // now draw the coronas using the query data for intensity info
6142 for (lightindex = 0;lightindex < range;lightindex++)
6144 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6147 rtlight = &light->rtlight;
6148 if (rtlight->corona_visibility <= 0)
6150 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6152 for (i = 0;i < r_refdef.scene.numlights;i++)
6154 rtlight = r_refdef.scene.lights[i];
6155 if (rtlight->corona_visibility <= 0)
6157 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6163 static dlight_t *R_Shadow_NewWorldLight(void)
6165 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
6168 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)
6172 // 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
6174 // validate parameters
6178 // copy to light properties
6179 VectorCopy(origin, light->origin);
6180 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
6181 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
6182 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
6184 light->color[0] = max(color[0], 0);
6185 light->color[1] = max(color[1], 0);
6186 light->color[2] = max(color[2], 0);
6188 light->color[0] = color[0];
6189 light->color[1] = color[1];
6190 light->color[2] = color[2];
6191 light->radius = max(radius, 0);
6192 light->style = style;
6193 light->shadow = shadowenable;
6194 light->corona = corona;
6195 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
6196 light->coronasizescale = coronasizescale;
6197 light->ambientscale = ambientscale;
6198 light->diffusescale = diffusescale;
6199 light->specularscale = specularscale;
6200 light->flags = flags;
6202 // update renderable light data
6203 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
6204 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);
6207 static void R_Shadow_FreeWorldLight(dlight_t *light)
6209 if (r_shadow_selectedlight == light)
6210 r_shadow_selectedlight = NULL;
6211 R_RTLight_Uncompile(&light->rtlight);
6212 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
6215 void R_Shadow_ClearWorldLights(void)
6219 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6220 for (lightindex = 0;lightindex < range;lightindex++)
6222 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6224 R_Shadow_FreeWorldLight(light);
6226 r_shadow_selectedlight = NULL;
6229 static void R_Shadow_SelectLight(dlight_t *light)
6231 if (r_shadow_selectedlight)
6232 r_shadow_selectedlight->selected = false;
6233 r_shadow_selectedlight = light;
6234 if (r_shadow_selectedlight)
6235 r_shadow_selectedlight->selected = true;
6238 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6240 // this is never batched (there can be only one)
6242 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
6243 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6244 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6247 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6252 skinframe_t *skinframe;
6255 // this is never batched (due to the ent parameter changing every time)
6256 // so numsurfaces == 1 and surfacelist[0] == lightnumber
6257 const dlight_t *light = (dlight_t *)ent;
6260 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
6263 VectorScale(light->color, intensity, spritecolor);
6264 if (VectorLength(spritecolor) < 0.1732f)
6265 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
6266 if (VectorLength(spritecolor) > 1.0f)
6267 VectorNormalize(spritecolor);
6269 // draw light sprite
6270 if (light->cubemapname[0] && !light->shadow)
6271 skinframe = r_editlights_sprcubemapnoshadowlight;
6272 else if (light->cubemapname[0])
6273 skinframe = r_editlights_sprcubemaplight;
6274 else if (!light->shadow)
6275 skinframe = r_editlights_sprnoshadowlight;
6277 skinframe = r_editlights_sprlight;
6279 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);
6280 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6282 // draw selection sprite if light is selected
6283 if (light->selected)
6285 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6286 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6287 // VorteX todo: add normalmode/realtime mode light overlay sprites?
6291 void R_Shadow_DrawLightSprites(void)
6295 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6296 for (lightindex = 0;lightindex < range;lightindex++)
6298 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6300 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
6302 if (!r_editlights_lockcursor)
6303 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
6306 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
6311 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6312 if (lightindex >= range)
6314 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6317 rtlight = &light->rtlight;
6318 //if (!(rtlight->flags & flag))
6320 VectorCopy(rtlight->shadoworigin, origin);
6321 *radius = rtlight->radius;
6322 VectorCopy(rtlight->color, color);
6326 static void R_Shadow_SelectLightInView(void)
6328 float bestrating, rating, temp[3];
6332 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6336 if (r_editlights_lockcursor)
6338 for (lightindex = 0;lightindex < range;lightindex++)
6340 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6343 VectorSubtract(light->origin, r_refdef.view.origin, temp);
6344 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
6347 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
6348 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1.0f)
6350 bestrating = rating;
6355 R_Shadow_SelectLight(best);
6358 void R_Shadow_LoadWorldLights(void)
6360 int n, a, style, shadow, flags;
6361 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
6362 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
6363 if (cl.worldmodel == NULL)
6365 Con_Print("No map loaded.\n");
6368 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6369 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6379 for (;COM_Parse(t, true) && strcmp(
6380 if (COM_Parse(t, true))
6382 if (com_token[0] == '!')
6385 origin[0] = atof(com_token+1);
6388 origin[0] = atof(com_token);
6393 while (*s && *s != '\n' && *s != '\r')
6399 // check for modifier flags
6406 #if _MSC_VER >= 1400
6407 #define sscanf sscanf_s
6409 cubemapname[sizeof(cubemapname)-1] = 0;
6410 #if MAX_QPATH != 128
6411 #error update this code if MAX_QPATH changes
6413 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
6414 #if _MSC_VER >= 1400
6415 , sizeof(cubemapname)
6417 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
6420 flags = LIGHTFLAG_REALTIMEMODE;
6428 coronasizescale = 0.25f;
6430 VectorClear(angles);
6433 if (a < 9 || !strcmp(cubemapname, "\"\""))
6435 // remove quotes on cubemapname
6436 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
6439 namelen = strlen(cubemapname) - 2;
6440 memmove(cubemapname, cubemapname + 1, namelen);
6441 cubemapname[namelen] = '\0';
6445 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);
6448 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6456 Con_Printf("invalid rtlights file \"%s\"\n", name);
6457 Mem_Free(lightsstring);
6461 void R_Shadow_SaveWorldLights(void)
6465 size_t bufchars, bufmaxchars;
6467 char name[MAX_QPATH];
6468 char line[MAX_INPUTLINE];
6469 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
6470 // I hate lines which are 3 times my screen size :( --blub
6473 if (cl.worldmodel == NULL)
6475 Con_Print("No map loaded.\n");
6478 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6479 bufchars = bufmaxchars = 0;
6481 for (lightindex = 0;lightindex < range;lightindex++)
6483 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6486 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
6487 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);
6488 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
6489 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]);
6491 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);
6492 if (bufchars + strlen(line) > bufmaxchars)
6494 bufmaxchars = bufchars + strlen(line) + 2048;
6496 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
6500 memcpy(buf, oldbuf, bufchars);
6506 memcpy(buf + bufchars, line, strlen(line));
6507 bufchars += strlen(line);
6511 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
6516 void R_Shadow_LoadLightsFile(void)
6519 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
6520 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
6521 if (cl.worldmodel == NULL)
6523 Con_Print("No map loaded.\n");
6526 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
6527 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6535 while (*s && *s != '\n' && *s != '\r')
6541 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);
6545 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);
6548 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
6549 radius = bound(15, radius, 4096);
6550 VectorScale(color, (2.0f / (8388608.0f)), color);
6551 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6559 Con_Printf("invalid lights file \"%s\"\n", name);
6560 Mem_Free(lightsstring);
6564 // tyrlite/hmap2 light types in the delay field
6565 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
6567 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
6579 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
6580 char key[256], value[MAX_INPUTLINE];
6583 if (cl.worldmodel == NULL)
6585 Con_Print("No map loaded.\n");
6588 // try to load a .ent file first
6589 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
6590 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
6591 // and if that is not found, fall back to the bsp file entity string
6593 data = cl.worldmodel->brush.entities;
6596 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
6598 type = LIGHTTYPE_MINUSX;
6599 origin[0] = origin[1] = origin[2] = 0;
6600 originhack[0] = originhack[1] = originhack[2] = 0;
6601 angles[0] = angles[1] = angles[2] = 0;
6602 color[0] = color[1] = color[2] = 1;
6603 light[0] = light[1] = light[2] = 1;light[3] = 300;
6604 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
6614 if (!COM_ParseToken_Simple(&data, false, false, true))
6616 if (com_token[0] == '}')
6617 break; // end of entity
6618 if (com_token[0] == '_')
6619 strlcpy(key, com_token + 1, sizeof(key));
6621 strlcpy(key, com_token, sizeof(key));
6622 while (key[strlen(key)-1] == ' ') // remove trailing spaces
6623 key[strlen(key)-1] = 0;
6624 if (!COM_ParseToken_Simple(&data, false, false, true))
6626 strlcpy(value, com_token, sizeof(value));
6628 // now that we have the key pair worked out...
6629 if (!strcmp("light", key))
6631 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
6635 light[0] = vec[0] * (1.0f / 256.0f);
6636 light[1] = vec[0] * (1.0f / 256.0f);
6637 light[2] = vec[0] * (1.0f / 256.0f);
6643 light[0] = vec[0] * (1.0f / 255.0f);
6644 light[1] = vec[1] * (1.0f / 255.0f);
6645 light[2] = vec[2] * (1.0f / 255.0f);
6649 else if (!strcmp("delay", key))
6651 else if (!strcmp("origin", key))
6652 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
6653 else if (!strcmp("angle", key))
6654 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
6655 else if (!strcmp("angles", key))
6656 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
6657 else if (!strcmp("color", key))
6658 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
6659 else if (!strcmp("wait", key))
6660 fadescale = atof(value);
6661 else if (!strcmp("classname", key))
6663 if (!strncmp(value, "light", 5))
6666 if (!strcmp(value, "light_fluoro"))
6671 overridecolor[0] = 1;
6672 overridecolor[1] = 1;
6673 overridecolor[2] = 1;
6675 if (!strcmp(value, "light_fluorospark"))
6680 overridecolor[0] = 1;
6681 overridecolor[1] = 1;
6682 overridecolor[2] = 1;
6684 if (!strcmp(value, "light_globe"))
6689 overridecolor[0] = 1;
6690 overridecolor[1] = 0.8;
6691 overridecolor[2] = 0.4;
6693 if (!strcmp(value, "light_flame_large_yellow"))
6698 overridecolor[0] = 1;
6699 overridecolor[1] = 0.5;
6700 overridecolor[2] = 0.1;
6702 if (!strcmp(value, "light_flame_small_yellow"))
6707 overridecolor[0] = 1;
6708 overridecolor[1] = 0.5;
6709 overridecolor[2] = 0.1;
6711 if (!strcmp(value, "light_torch_small_white"))
6716 overridecolor[0] = 1;
6717 overridecolor[1] = 0.5;
6718 overridecolor[2] = 0.1;
6720 if (!strcmp(value, "light_torch_small_walltorch"))
6725 overridecolor[0] = 1;
6726 overridecolor[1] = 0.5;
6727 overridecolor[2] = 0.1;
6731 else if (!strcmp("style", key))
6732 style = atoi(value);
6733 else if (!strcmp("skin", key))
6734 skin = (int)atof(value);
6735 else if (!strcmp("pflags", key))
6736 pflags = (int)atof(value);
6737 //else if (!strcmp("effects", key))
6738 // effects = (int)atof(value);
6739 else if (cl.worldmodel->type == mod_brushq3)
6741 if (!strcmp("scale", key))
6742 lightscale = atof(value);
6743 if (!strcmp("fade", key))
6744 fadescale = atof(value);
6749 if (lightscale <= 0)
6753 if (color[0] == color[1] && color[0] == color[2])
6755 color[0] *= overridecolor[0];
6756 color[1] *= overridecolor[1];
6757 color[2] *= overridecolor[2];
6759 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
6760 color[0] = color[0] * light[0];
6761 color[1] = color[1] * light[1];
6762 color[2] = color[2] * light[2];
6765 case LIGHTTYPE_MINUSX:
6767 case LIGHTTYPE_RECIPX:
6769 VectorScale(color, (1.0f / 16.0f), color);
6771 case LIGHTTYPE_RECIPXX:
6773 VectorScale(color, (1.0f / 16.0f), color);
6776 case LIGHTTYPE_NONE:
6780 case LIGHTTYPE_MINUSXX:
6783 VectorAdd(origin, originhack, origin);
6785 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);
6788 Mem_Free(entfiledata);
6792 static void R_Shadow_SetCursorLocationForView(void)
6795 vec3_t dest, endpos;
6797 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
6798 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
6799 if (trace.fraction < 1)
6801 dist = trace.fraction * r_editlights_cursordistance.value;
6802 push = r_editlights_cursorpushback.value;
6806 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
6807 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
6811 VectorClear( endpos );
6813 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6814 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6815 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6818 void R_Shadow_UpdateWorldLightSelection(void)
6820 if (r_editlights.integer)
6822 R_Shadow_SetCursorLocationForView();
6823 R_Shadow_SelectLightInView();
6826 R_Shadow_SelectLight(NULL);
6829 static void R_Shadow_EditLights_Clear_f(void)
6831 R_Shadow_ClearWorldLights();
6834 void R_Shadow_EditLights_Reload_f(void)
6838 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
6839 R_Shadow_ClearWorldLights();
6840 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
6842 R_Shadow_LoadWorldLights();
6843 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6844 R_Shadow_LoadLightsFile();
6846 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
6848 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6849 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6853 static void R_Shadow_EditLights_Save_f(void)
6857 R_Shadow_SaveWorldLights();
6860 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6862 R_Shadow_ClearWorldLights();
6863 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6866 static void R_Shadow_EditLights_ImportLightsFile_f(void)
6868 R_Shadow_ClearWorldLights();
6869 R_Shadow_LoadLightsFile();
6872 static void R_Shadow_EditLights_Spawn_f(void)
6875 if (!r_editlights.integer)
6877 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6880 if (Cmd_Argc() != 1)
6882 Con_Print("r_editlights_spawn does not take parameters\n");
6885 color[0] = color[1] = color[2] = 1;
6886 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6889 static void R_Shadow_EditLights_Edit_f(void)
6891 vec3_t origin, angles, color;
6892 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6893 int style, shadows, flags, normalmode, realtimemode;
6894 char cubemapname[MAX_INPUTLINE];
6895 if (!r_editlights.integer)
6897 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6900 if (!r_shadow_selectedlight)
6902 Con_Print("No selected light.\n");
6905 VectorCopy(r_shadow_selectedlight->origin, origin);
6906 VectorCopy(r_shadow_selectedlight->angles, angles);
6907 VectorCopy(r_shadow_selectedlight->color, color);
6908 radius = r_shadow_selectedlight->radius;
6909 style = r_shadow_selectedlight->style;
6910 if (r_shadow_selectedlight->cubemapname)
6911 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6914 shadows = r_shadow_selectedlight->shadow;
6915 corona = r_shadow_selectedlight->corona;
6916 coronasizescale = r_shadow_selectedlight->coronasizescale;
6917 ambientscale = r_shadow_selectedlight->ambientscale;
6918 diffusescale = r_shadow_selectedlight->diffusescale;
6919 specularscale = r_shadow_selectedlight->specularscale;
6920 flags = r_shadow_selectedlight->flags;
6921 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6922 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6923 if (!strcmp(Cmd_Argv(1), "origin"))
6925 if (Cmd_Argc() != 5)
6927 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6930 origin[0] = atof(Cmd_Argv(2));
6931 origin[1] = atof(Cmd_Argv(3));
6932 origin[2] = atof(Cmd_Argv(4));
6934 else if (!strcmp(Cmd_Argv(1), "originscale"))
6936 if (Cmd_Argc() != 5)
6938 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6941 origin[0] *= atof(Cmd_Argv(2));
6942 origin[1] *= atof(Cmd_Argv(3));
6943 origin[2] *= atof(Cmd_Argv(4));
6945 else if (!strcmp(Cmd_Argv(1), "originx"))
6947 if (Cmd_Argc() != 3)
6949 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6952 origin[0] = atof(Cmd_Argv(2));
6954 else if (!strcmp(Cmd_Argv(1), "originy"))
6956 if (Cmd_Argc() != 3)
6958 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6961 origin[1] = atof(Cmd_Argv(2));
6963 else if (!strcmp(Cmd_Argv(1), "originz"))
6965 if (Cmd_Argc() != 3)
6967 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6970 origin[2] = atof(Cmd_Argv(2));
6972 else if (!strcmp(Cmd_Argv(1), "move"))
6974 if (Cmd_Argc() != 5)
6976 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6979 origin[0] += atof(Cmd_Argv(2));
6980 origin[1] += atof(Cmd_Argv(3));
6981 origin[2] += atof(Cmd_Argv(4));
6983 else if (!strcmp(Cmd_Argv(1), "movex"))
6985 if (Cmd_Argc() != 3)
6987 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6990 origin[0] += atof(Cmd_Argv(2));
6992 else if (!strcmp(Cmd_Argv(1), "movey"))
6994 if (Cmd_Argc() != 3)
6996 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6999 origin[1] += atof(Cmd_Argv(2));
7001 else if (!strcmp(Cmd_Argv(1), "movez"))
7003 if (Cmd_Argc() != 3)
7005 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7008 origin[2] += atof(Cmd_Argv(2));
7010 else if (!strcmp(Cmd_Argv(1), "angles"))
7012 if (Cmd_Argc() != 5)
7014 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
7017 angles[0] = atof(Cmd_Argv(2));
7018 angles[1] = atof(Cmd_Argv(3));
7019 angles[2] = atof(Cmd_Argv(4));
7021 else if (!strcmp(Cmd_Argv(1), "anglesx"))
7023 if (Cmd_Argc() != 3)
7025 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7028 angles[0] = atof(Cmd_Argv(2));
7030 else if (!strcmp(Cmd_Argv(1), "anglesy"))
7032 if (Cmd_Argc() != 3)
7034 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7037 angles[1] = atof(Cmd_Argv(2));
7039 else if (!strcmp(Cmd_Argv(1), "anglesz"))
7041 if (Cmd_Argc() != 3)
7043 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7046 angles[2] = atof(Cmd_Argv(2));
7048 else if (!strcmp(Cmd_Argv(1), "color"))
7050 if (Cmd_Argc() != 5)
7052 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
7055 color[0] = atof(Cmd_Argv(2));
7056 color[1] = atof(Cmd_Argv(3));
7057 color[2] = atof(Cmd_Argv(4));
7059 else if (!strcmp(Cmd_Argv(1), "radius"))
7061 if (Cmd_Argc() != 3)
7063 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7066 radius = atof(Cmd_Argv(2));
7068 else if (!strcmp(Cmd_Argv(1), "colorscale"))
7070 if (Cmd_Argc() == 3)
7072 double scale = atof(Cmd_Argv(2));
7079 if (Cmd_Argc() != 5)
7081 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
7084 color[0] *= atof(Cmd_Argv(2));
7085 color[1] *= atof(Cmd_Argv(3));
7086 color[2] *= atof(Cmd_Argv(4));
7089 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
7091 if (Cmd_Argc() != 3)
7093 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7096 radius *= atof(Cmd_Argv(2));
7098 else if (!strcmp(Cmd_Argv(1), "style"))
7100 if (Cmd_Argc() != 3)
7102 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7105 style = atoi(Cmd_Argv(2));
7107 else if (!strcmp(Cmd_Argv(1), "cubemap"))
7111 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7114 if (Cmd_Argc() == 3)
7115 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
7119 else if (!strcmp(Cmd_Argv(1), "shadows"))
7121 if (Cmd_Argc() != 3)
7123 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7126 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7128 else if (!strcmp(Cmd_Argv(1), "corona"))
7130 if (Cmd_Argc() != 3)
7132 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7135 corona = atof(Cmd_Argv(2));
7137 else if (!strcmp(Cmd_Argv(1), "coronasize"))
7139 if (Cmd_Argc() != 3)
7141 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7144 coronasizescale = atof(Cmd_Argv(2));
7146 else if (!strcmp(Cmd_Argv(1), "ambient"))
7148 if (Cmd_Argc() != 3)
7150 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7153 ambientscale = atof(Cmd_Argv(2));
7155 else if (!strcmp(Cmd_Argv(1), "diffuse"))
7157 if (Cmd_Argc() != 3)
7159 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7162 diffusescale = atof(Cmd_Argv(2));
7164 else if (!strcmp(Cmd_Argv(1), "specular"))
7166 if (Cmd_Argc() != 3)
7168 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7171 specularscale = atof(Cmd_Argv(2));
7173 else if (!strcmp(Cmd_Argv(1), "normalmode"))
7175 if (Cmd_Argc() != 3)
7177 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7180 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7182 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
7184 if (Cmd_Argc() != 3)
7186 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7189 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7193 Con_Print("usage: r_editlights_edit [property] [value]\n");
7194 Con_Print("Selected light's properties:\n");
7195 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7196 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7197 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7198 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
7199 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
7200 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
7201 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
7202 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
7203 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
7204 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
7205 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
7206 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
7207 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
7208 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
7211 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
7212 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
7215 static void R_Shadow_EditLights_EditAll_f(void)
7218 dlight_t *light, *oldselected;
7221 if (!r_editlights.integer)
7223 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
7227 oldselected = r_shadow_selectedlight;
7228 // EditLights doesn't seem to have a "remove" command or something so:
7229 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7230 for (lightindex = 0;lightindex < range;lightindex++)
7232 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7235 R_Shadow_SelectLight(light);
7236 R_Shadow_EditLights_Edit_f();
7238 // return to old selected (to not mess editing once selection is locked)
7239 R_Shadow_SelectLight(oldselected);
7242 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
7244 int lightnumber, lightcount;
7245 size_t lightindex, range;
7250 if (!r_editlights.integer)
7253 // update cvars so QC can query them
7254 if (r_shadow_selectedlight)
7256 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7257 Cvar_SetQuick(&r_editlights_current_origin, temp);
7258 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7259 Cvar_SetQuick(&r_editlights_current_angles, temp);
7260 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7261 Cvar_SetQuick(&r_editlights_current_color, temp);
7262 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
7263 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
7264 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
7265 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
7266 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
7267 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
7268 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
7269 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
7270 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
7271 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
7272 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
7275 // draw properties on screen
7276 if (!r_editlights_drawproperties.integer)
7278 x = vid_conwidth.value - 320;
7280 DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
7283 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7284 for (lightindex = 0;lightindex < range;lightindex++)
7286 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7289 if (light == r_shadow_selectedlight)
7290 lightnumber = (int)lightindex;
7293 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;
7294 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;
7296 if (r_shadow_selectedlight == NULL)
7298 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;
7299 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;
7300 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;
7301 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;
7302 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;
7303 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;
7304 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;
7305 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;
7306 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;
7307 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;
7308 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;
7309 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;
7310 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;
7311 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;
7312 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;
7314 dpsnprintf(temp, sizeof(temp), "Render stats\n"); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7315 dpsnprintf(temp, sizeof(temp), "Current color: %.3f %.3f %.3f\n", r_shadow_selectedlight->rtlight.currentcolor[0], r_shadow_selectedlight->rtlight.currentcolor[1], r_shadow_selectedlight->rtlight.currentcolor[2]); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7316 dpsnprintf(temp, sizeof(temp), "Shadow size : %ix%ix6\n", r_shadow_selectedlight->rtlight.shadowmapatlassidesize, r_shadow_selectedlight->rtlight.shadowmapatlassidesize); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7317 dpsnprintf(temp, sizeof(temp), "World surfs : %i\n", r_shadow_selectedlight->rtlight.cached_numsurfaces); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7318 dpsnprintf(temp, sizeof(temp), "Shadow ents : %i + %i noself\n", r_shadow_selectedlight->rtlight.cached_numshadowentities, r_shadow_selectedlight->rtlight.cached_numshadowentities_noselfshadow); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7319 dpsnprintf(temp, sizeof(temp), "Lit ents : %i + %i noself\n", r_shadow_selectedlight->rtlight.cached_numlightentities, r_shadow_selectedlight->rtlight.cached_numlightentities_noselfshadow); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7320 dpsnprintf(temp, sizeof(temp), "BG photons : %.3f\n", r_shadow_selectedlight->rtlight.bouncegrid_photons); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7321 dpsnprintf(temp, sizeof(temp), "BG radius : %.0f\n", r_shadow_selectedlight->rtlight.bouncegrid_effectiveradius); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7322 dpsnprintf(temp, sizeof(temp), "BG color : %.3f %.3f %.3f\n", r_shadow_selectedlight->rtlight.bouncegrid_photoncolor[0], r_shadow_selectedlight->rtlight.bouncegrid_photoncolor[1], r_shadow_selectedlight->rtlight.bouncegrid_photoncolor[2]); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7323 dpsnprintf(temp, sizeof(temp), "BG stats : %i traces %i hits\n", r_shadow_selectedlight->rtlight.bouncegrid_traces, r_shadow_selectedlight->rtlight.bouncegrid_hits); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7326 static void R_Shadow_EditLights_ToggleShadow_f(void)
7328 if (!r_editlights.integer)
7330 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7333 if (!r_shadow_selectedlight)
7335 Con_Print("No selected light.\n");
7338 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);
7341 static void R_Shadow_EditLights_ToggleCorona_f(void)
7343 if (!r_editlights.integer)
7345 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7348 if (!r_shadow_selectedlight)
7350 Con_Print("No selected light.\n");
7353 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);
7356 static void R_Shadow_EditLights_Remove_f(void)
7358 if (!r_editlights.integer)
7360 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
7363 if (!r_shadow_selectedlight)
7365 Con_Print("No selected light.\n");
7368 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
7369 r_shadow_selectedlight = NULL;
7372 static void R_Shadow_EditLights_Help_f(void)
7375 "Documentation on r_editlights system:\n"
7377 "r_editlights : enable/disable editing mode\n"
7378 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
7379 "r_editlights_cursorpushback : push back cursor this far from surface\n"
7380 "r_editlights_cursorpushoff : push cursor off surface this far\n"
7381 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
7382 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
7384 "r_editlights_help : this help\n"
7385 "r_editlights_clear : remove all lights\n"
7386 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
7387 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
7388 "r_editlights_save : save to .rtlights file\n"
7389 "r_editlights_spawn : create a light with default settings\n"
7390 "r_editlights_edit command : edit selected light - more documentation below\n"
7391 "r_editlights_remove : remove selected light\n"
7392 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
7393 "r_editlights_importlightentitiesfrommap : reload light entities\n"
7394 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
7396 "origin x y z : set light location\n"
7397 "originx x: set x component of light location\n"
7398 "originy y: set y component of light location\n"
7399 "originz z: set z component of light location\n"
7400 "move x y z : adjust light location\n"
7401 "movex x: adjust x component of light location\n"
7402 "movey y: adjust y component of light location\n"
7403 "movez z: adjust z component of light location\n"
7404 "angles x y z : set light angles\n"
7405 "anglesx x: set x component of light angles\n"
7406 "anglesy y: set y component of light angles\n"
7407 "anglesz z: set z component of light angles\n"
7408 "color r g b : set color of light (can be brighter than 1 1 1)\n"
7409 "radius radius : set radius (size) of light\n"
7410 "colorscale grey : multiply color of light (1 does nothing)\n"
7411 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
7412 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
7413 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
7414 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
7415 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
7416 "cubemap basename : set filter cubemap of light\n"
7417 "shadows 1/0 : turn on/off shadows\n"
7418 "corona n : set corona intensity\n"
7419 "coronasize n : set corona size (0-1)\n"
7420 "ambient n : set ambient intensity (0-1)\n"
7421 "diffuse n : set diffuse intensity (0-1)\n"
7422 "specular n : set specular intensity (0-1)\n"
7423 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
7424 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
7425 "<nothing> : print light properties to console\n"
7429 static void R_Shadow_EditLights_CopyInfo_f(void)
7431 if (!r_editlights.integer)
7433 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
7436 if (!r_shadow_selectedlight)
7438 Con_Print("No selected light.\n");
7441 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
7442 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
7443 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
7444 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
7445 if (r_shadow_selectedlight->cubemapname)
7446 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
7448 r_shadow_bufferlight.cubemapname[0] = 0;
7449 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
7450 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
7451 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
7452 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
7453 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
7454 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
7455 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
7458 static void R_Shadow_EditLights_PasteInfo_f(void)
7460 if (!r_editlights.integer)
7462 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
7465 if (!r_shadow_selectedlight)
7467 Con_Print("No selected light.\n");
7470 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);
7473 static void R_Shadow_EditLights_Lock_f(void)
7475 if (!r_editlights.integer)
7477 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
7480 if (r_editlights_lockcursor)
7482 r_editlights_lockcursor = false;
7485 if (!r_shadow_selectedlight)
7487 Con_Print("No selected light to lock on.\n");
7490 r_editlights_lockcursor = true;
7493 static void R_Shadow_EditLights_Init(void)
7495 Cvar_RegisterVariable(&r_editlights);
7496 Cvar_RegisterVariable(&r_editlights_cursordistance);
7497 Cvar_RegisterVariable(&r_editlights_cursorpushback);
7498 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
7499 Cvar_RegisterVariable(&r_editlights_cursorgrid);
7500 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
7501 Cvar_RegisterVariable(&r_editlights_drawproperties);
7502 Cvar_RegisterVariable(&r_editlights_current_origin);
7503 Cvar_RegisterVariable(&r_editlights_current_angles);
7504 Cvar_RegisterVariable(&r_editlights_current_color);
7505 Cvar_RegisterVariable(&r_editlights_current_radius);
7506 Cvar_RegisterVariable(&r_editlights_current_corona);
7507 Cvar_RegisterVariable(&r_editlights_current_coronasize);
7508 Cvar_RegisterVariable(&r_editlights_current_style);
7509 Cvar_RegisterVariable(&r_editlights_current_shadows);
7510 Cvar_RegisterVariable(&r_editlights_current_cubemap);
7511 Cvar_RegisterVariable(&r_editlights_current_ambient);
7512 Cvar_RegisterVariable(&r_editlights_current_diffuse);
7513 Cvar_RegisterVariable(&r_editlights_current_specular);
7514 Cvar_RegisterVariable(&r_editlights_current_normalmode);
7515 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
7516 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
7517 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
7518 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)");
7519 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
7520 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
7521 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
7522 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)");
7523 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
7524 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
7525 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
7526 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
7527 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
7528 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
7529 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)");
7530 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
7536 =============================================================================
7540 =============================================================================
7543 void R_CompleteLightPoint(float *ambient, float *diffuse, float *lightdir, const vec3_t p, const int flags, float lightmapintensity, float ambientintensity)
7545 int i, numlights, flag, q;
7548 float relativepoint[3];
7553 float sa[3], sx[3], sy[3], sz[3], sd[3];
7556 // use first order spherical harmonics to combine directional lights
7557 for (q = 0; q < 3; q++)
7558 sa[q] = sx[q] = sy[q] = sz[q] = sd[q] = 0;
7560 if (flags & LP_LIGHTMAP)
7562 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7564 float tempambient[3];
7565 for (q = 0; q < 3; q++)
7566 tempambient[q] = color[q] = relativepoint[q] = 0;
7567 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
7568 // calculate a weighted average light direction as well
7569 intensity = VectorLength(color);
7570 for (q = 0; q < 3; q++)
7572 sa[q] += (0.5f * color[q] + tempambient[q]) * lightmapintensity;
7573 sx[q] += (relativepoint[0] * color[q]) * lightmapintensity;
7574 sy[q] += (relativepoint[1] * color[q]) * lightmapintensity;
7575 sz[q] += (relativepoint[2] * color[q]) * lightmapintensity;
7576 sd[q] += (intensity * relativepoint[q]) * lightmapintensity;
7581 // unlit map - fullbright but scaled by lightmapintensity
7582 for (q = 0; q < 3; q++)
7583 sa[q] += lightmapintensity;
7587 if (flags & LP_RTWORLD)
7589 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7590 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7591 for (i = 0; i < numlights; i++)
7593 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7596 light = &dlight->rtlight;
7597 if (!(light->flags & flag))
7600 lightradius2 = light->radius * light->radius;
7601 VectorSubtract(light->shadoworigin, p, relativepoint);
7602 dist2 = VectorLength2(relativepoint);
7603 if (dist2 >= lightradius2)
7605 dist = sqrt(dist2) / light->radius;
7606 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
7607 if (intensity <= 0.0f)
7609 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
7611 for (q = 0; q < 3; q++)
7612 color[q] = light->currentcolor[q] * intensity;
7613 intensity = VectorLength(color);
7614 VectorNormalize(relativepoint);
7615 for (q = 0; q < 3; q++)
7617 sa[q] += 0.5f * color[q];
7618 sx[q] += relativepoint[0] * color[q];
7619 sy[q] += relativepoint[1] * color[q];
7620 sz[q] += relativepoint[2] * color[q];
7621 sd[q] += intensity * relativepoint[q];
7624 // FIXME: sample bouncegrid too!
7627 if (flags & LP_DYNLIGHT)
7630 for (i = 0;i < r_refdef.scene.numlights;i++)
7632 light = r_refdef.scene.lights[i];
7634 lightradius2 = light->radius * light->radius;
7635 VectorSubtract(light->shadoworigin, p, relativepoint);
7636 dist2 = VectorLength2(relativepoint);
7637 if (dist2 >= lightradius2)
7639 dist = sqrt(dist2) / light->radius;
7640 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
7641 if (intensity <= 0.0f)
7643 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
7645 for (q = 0; q < 3; q++)
7646 color[q] = light->currentcolor[q] * intensity;
7647 intensity = VectorLength(color);
7648 VectorNormalize(relativepoint);
7649 for (q = 0; q < 3; q++)
7651 sa[q] += 0.5f * color[q];
7652 sx[q] += relativepoint[0] * color[q];
7653 sy[q] += relativepoint[1] * color[q];
7654 sz[q] += relativepoint[2] * color[q];
7655 sd[q] += intensity * relativepoint[q];
7660 // calculate the weighted-average light direction (bentnormal)
7661 for (q = 0; q < 3; q++)
7662 lightdir[q] = sd[q];
7663 VectorNormalize(lightdir);
7664 for (q = 0; q < 3; q++)
7666 // extract the diffuse color along the chosen direction and scale it
7667 diffuse[q] = (lightdir[0] * sx[q] + lightdir[1] * sy[q] + lightdir[2] * sz[q]);
7668 // subtract some of diffuse from ambient
7669 ambient[q] = sa[q] + -0.333f * diffuse[q] + ambientintensity;