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;
748 r_shadow_bouncegrid_state.maxsplatpaths = 0;
749 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
750 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
751 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
752 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
753 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
754 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
755 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
756 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
757 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
758 R_Shadow_EditLights_Reload_f();
761 void R_Shadow_Init(void)
763 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
764 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
765 Cvar_RegisterVariable(&r_shadow_usebihculling);
766 Cvar_RegisterVariable(&r_shadow_usenormalmap);
767 Cvar_RegisterVariable(&r_shadow_debuglight);
768 Cvar_RegisterVariable(&r_shadow_deferred);
769 Cvar_RegisterVariable(&r_shadow_gloss);
770 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
771 Cvar_RegisterVariable(&r_shadow_glossintensity);
772 Cvar_RegisterVariable(&r_shadow_glossexponent);
773 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
774 Cvar_RegisterVariable(&r_shadow_glossexact);
775 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
776 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
777 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
778 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
779 Cvar_RegisterVariable(&r_shadow_projectdistance);
780 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
781 Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
782 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
783 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
784 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
785 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
786 Cvar_RegisterVariable(&r_shadow_realtime_world);
787 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
788 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
789 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
790 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
791 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
792 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
793 Cvar_RegisterVariable(&r_shadow_scissor);
794 Cvar_RegisterVariable(&r_shadow_shadowmapping);
795 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
796 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
797 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
798 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
799 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
800 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
801 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
802 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturesize);
803 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
804 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
805 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
806 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
807 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
808 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
809 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
810 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
811 Cvar_RegisterVariable(&r_shadow_polygonfactor);
812 Cvar_RegisterVariable(&r_shadow_polygonoffset);
813 Cvar_RegisterVariable(&r_shadow_texture3d);
814 Cvar_RegisterVariable(&r_shadow_culllights_pvs);
815 Cvar_RegisterVariable(&r_shadow_culllights_trace);
816 Cvar_RegisterVariable(&r_shadow_culllights_trace_eyejitter);
817 Cvar_RegisterVariable(&r_shadow_culllights_trace_enlarge);
818 Cvar_RegisterVariable(&r_shadow_culllights_trace_samples);
819 Cvar_RegisterVariable(&r_shadow_culllights_trace_tempsamples);
820 Cvar_RegisterVariable(&r_shadow_culllights_trace_delay);
821 Cvar_RegisterVariable(&r_shadow_bouncegrid);
822 Cvar_RegisterVariable(&r_shadow_bouncegrid_blur);
823 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
824 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_bounceminimumintensity);
825 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_culllightpaths);
826 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_directionalshading);
827 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_dlightparticlemultiplier);
828 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_hitmodels);
829 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_lightradiusscale);
830 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxbounce);
831 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxphotons);
832 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_quality);
833 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_spacing);
834 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_updateinterval);
835 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_x);
836 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_y);
837 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_z);
838 Cvar_RegisterVariable(&r_shadow_bouncegrid_floatcolors);
839 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
840 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
841 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize_conespread);
842 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize_initial);
843 Cvar_RegisterVariable(&r_shadow_bouncegrid_normalizevectors);
844 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
845 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
846 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_seed);
847 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_type);
848 Cvar_RegisterVariable(&r_shadow_bouncegrid_sortlightpaths);
849 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
850 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_bounceminimumintensity);
851 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
852 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
853 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
854 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxphotons);
855 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_quality);
856 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_spacing);
857 Cvar_RegisterVariable(&r_coronas);
858 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
859 Cvar_RegisterVariable(&r_coronas_occlusionquery);
860 Cvar_RegisterVariable(&gl_flashblend);
861 Cvar_RegisterVariable(&gl_ext_separatestencil);
862 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
863 R_Shadow_EditLights_Init();
864 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
865 r_shadow_scenemaxlights = 0;
866 r_shadow_scenenumlights = 0;
867 r_shadow_scenelightlist = NULL;
868 maxshadowtriangles = 0;
869 shadowelements = NULL;
870 maxshadowvertices = 0;
871 shadowvertex3f = NULL;
879 shadowmarklist = NULL;
884 shadowsideslist = NULL;
885 r_shadow_buffer_numleafpvsbytes = 0;
886 r_shadow_buffer_visitingleafpvs = NULL;
887 r_shadow_buffer_leafpvs = NULL;
888 r_shadow_buffer_leaflist = NULL;
889 r_shadow_buffer_numsurfacepvsbytes = 0;
890 r_shadow_buffer_surfacepvs = NULL;
891 r_shadow_buffer_surfacelist = NULL;
892 r_shadow_buffer_surfacesides = NULL;
893 r_shadow_buffer_shadowtrispvs = NULL;
894 r_shadow_buffer_lighttrispvs = NULL;
895 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
898 matrix4x4_t matrix_attenuationxyz =
901 {0.5, 0.0, 0.0, 0.5},
902 {0.0, 0.5, 0.0, 0.5},
903 {0.0, 0.0, 0.5, 0.5},
908 matrix4x4_t matrix_attenuationz =
911 {0.0, 0.0, 0.5, 0.5},
912 {0.0, 0.0, 0.0, 0.5},
913 {0.0, 0.0, 0.0, 0.5},
918 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
920 numvertices = ((numvertices + 255) & ~255) * vertscale;
921 numtriangles = ((numtriangles + 255) & ~255) * triscale;
922 // make sure shadowelements is big enough for this volume
923 if (maxshadowtriangles < numtriangles)
925 maxshadowtriangles = numtriangles;
927 Mem_Free(shadowelements);
928 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
930 // make sure shadowvertex3f is big enough for this volume
931 if (maxshadowvertices < numvertices)
933 maxshadowvertices = numvertices;
935 Mem_Free(shadowvertex3f);
936 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
940 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
942 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
943 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
944 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
945 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
946 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
948 if (r_shadow_buffer_visitingleafpvs)
949 Mem_Free(r_shadow_buffer_visitingleafpvs);
950 if (r_shadow_buffer_leafpvs)
951 Mem_Free(r_shadow_buffer_leafpvs);
952 if (r_shadow_buffer_leaflist)
953 Mem_Free(r_shadow_buffer_leaflist);
954 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
955 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
956 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
957 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
959 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
961 if (r_shadow_buffer_surfacepvs)
962 Mem_Free(r_shadow_buffer_surfacepvs);
963 if (r_shadow_buffer_surfacelist)
964 Mem_Free(r_shadow_buffer_surfacelist);
965 if (r_shadow_buffer_surfacesides)
966 Mem_Free(r_shadow_buffer_surfacesides);
967 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
968 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
969 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
970 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
972 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
974 if (r_shadow_buffer_shadowtrispvs)
975 Mem_Free(r_shadow_buffer_shadowtrispvs);
976 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
977 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
979 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
981 if (r_shadow_buffer_lighttrispvs)
982 Mem_Free(r_shadow_buffer_lighttrispvs);
983 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
984 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
988 void R_Shadow_PrepareShadowMark(int numtris)
990 // make sure shadowmark is big enough for this volume
991 if (maxshadowmark < numtris)
993 maxshadowmark = numtris;
995 Mem_Free(shadowmark);
997 Mem_Free(shadowmarklist);
998 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
999 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
1000 shadowmarkcount = 0;
1003 // if shadowmarkcount wrapped we clear the array and adjust accordingly
1004 if (shadowmarkcount == 0)
1006 shadowmarkcount = 1;
1007 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
1012 void R_Shadow_PrepareShadowSides(int numtris)
1014 if (maxshadowsides < numtris)
1016 maxshadowsides = numtris;
1018 Mem_Free(shadowsides);
1019 if (shadowsideslist)
1020 Mem_Free(shadowsideslist);
1021 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
1022 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
1027 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)
1030 int outtriangles = 0, outvertices = 0;
1032 const float *vertex;
1033 float ratio, direction[3], projectvector[3];
1035 if (projectdirection)
1036 VectorScale(projectdirection, projectdistance, projectvector);
1038 VectorClear(projectvector);
1040 // create the vertices
1041 if (projectdirection)
1043 for (i = 0;i < numshadowmarktris;i++)
1045 element = inelement3i + shadowmarktris[i] * 3;
1046 for (j = 0;j < 3;j++)
1048 if (vertexupdate[element[j]] != vertexupdatenum)
1050 vertexupdate[element[j]] = vertexupdatenum;
1051 vertexremap[element[j]] = outvertices;
1052 vertex = invertex3f + element[j] * 3;
1053 // project one copy of the vertex according to projectvector
1054 VectorCopy(vertex, outvertex3f);
1055 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1064 for (i = 0;i < numshadowmarktris;i++)
1066 element = inelement3i + shadowmarktris[i] * 3;
1067 for (j = 0;j < 3;j++)
1069 if (vertexupdate[element[j]] != vertexupdatenum)
1071 vertexupdate[element[j]] = vertexupdatenum;
1072 vertexremap[element[j]] = outvertices;
1073 vertex = invertex3f + element[j] * 3;
1074 // project one copy of the vertex to the sphere radius of the light
1075 // (FIXME: would projecting it to the light box be better?)
1076 VectorSubtract(vertex, projectorigin, direction);
1077 ratio = projectdistance / VectorLength(direction);
1078 VectorCopy(vertex, outvertex3f);
1079 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1087 if (r_shadow_frontsidecasting.integer)
1089 for (i = 0;i < numshadowmarktris;i++)
1091 int remappedelement[3];
1093 const int *neighbortriangle;
1095 markindex = shadowmarktris[i] * 3;
1096 element = inelement3i + markindex;
1097 neighbortriangle = inneighbor3i + markindex;
1098 // output the front and back triangles
1099 outelement3i[0] = vertexremap[element[0]];
1100 outelement3i[1] = vertexremap[element[1]];
1101 outelement3i[2] = vertexremap[element[2]];
1102 outelement3i[3] = vertexremap[element[2]] + 1;
1103 outelement3i[4] = vertexremap[element[1]] + 1;
1104 outelement3i[5] = vertexremap[element[0]] + 1;
1108 // output the sides (facing outward from this triangle)
1109 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1111 remappedelement[0] = vertexremap[element[0]];
1112 remappedelement[1] = vertexremap[element[1]];
1113 outelement3i[0] = remappedelement[1];
1114 outelement3i[1] = remappedelement[0];
1115 outelement3i[2] = remappedelement[0] + 1;
1116 outelement3i[3] = remappedelement[1];
1117 outelement3i[4] = remappedelement[0] + 1;
1118 outelement3i[5] = remappedelement[1] + 1;
1123 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1125 remappedelement[1] = vertexremap[element[1]];
1126 remappedelement[2] = vertexremap[element[2]];
1127 outelement3i[0] = remappedelement[2];
1128 outelement3i[1] = remappedelement[1];
1129 outelement3i[2] = remappedelement[1] + 1;
1130 outelement3i[3] = remappedelement[2];
1131 outelement3i[4] = remappedelement[1] + 1;
1132 outelement3i[5] = remappedelement[2] + 1;
1137 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1139 remappedelement[0] = vertexremap[element[0]];
1140 remappedelement[2] = vertexremap[element[2]];
1141 outelement3i[0] = remappedelement[0];
1142 outelement3i[1] = remappedelement[2];
1143 outelement3i[2] = remappedelement[2] + 1;
1144 outelement3i[3] = remappedelement[0];
1145 outelement3i[4] = remappedelement[2] + 1;
1146 outelement3i[5] = remappedelement[0] + 1;
1155 for (i = 0;i < numshadowmarktris;i++)
1157 int remappedelement[3];
1159 const int *neighbortriangle;
1161 markindex = shadowmarktris[i] * 3;
1162 element = inelement3i + markindex;
1163 neighbortriangle = inneighbor3i + markindex;
1164 // output the front and back triangles
1165 outelement3i[0] = vertexremap[element[2]];
1166 outelement3i[1] = vertexremap[element[1]];
1167 outelement3i[2] = vertexremap[element[0]];
1168 outelement3i[3] = vertexremap[element[0]] + 1;
1169 outelement3i[4] = vertexremap[element[1]] + 1;
1170 outelement3i[5] = vertexremap[element[2]] + 1;
1174 // output the sides (facing outward from this triangle)
1175 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1177 remappedelement[0] = vertexremap[element[0]];
1178 remappedelement[1] = vertexremap[element[1]];
1179 outelement3i[0] = remappedelement[0];
1180 outelement3i[1] = remappedelement[1];
1181 outelement3i[2] = remappedelement[1] + 1;
1182 outelement3i[3] = remappedelement[0];
1183 outelement3i[4] = remappedelement[1] + 1;
1184 outelement3i[5] = remappedelement[0] + 1;
1189 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1191 remappedelement[1] = vertexremap[element[1]];
1192 remappedelement[2] = vertexremap[element[2]];
1193 outelement3i[0] = remappedelement[1];
1194 outelement3i[1] = remappedelement[2];
1195 outelement3i[2] = remappedelement[2] + 1;
1196 outelement3i[3] = remappedelement[1];
1197 outelement3i[4] = remappedelement[2] + 1;
1198 outelement3i[5] = remappedelement[1] + 1;
1203 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1205 remappedelement[0] = vertexremap[element[0]];
1206 remappedelement[2] = vertexremap[element[2]];
1207 outelement3i[0] = remappedelement[2];
1208 outelement3i[1] = remappedelement[0];
1209 outelement3i[2] = remappedelement[0] + 1;
1210 outelement3i[3] = remappedelement[2];
1211 outelement3i[4] = remappedelement[0] + 1;
1212 outelement3i[5] = remappedelement[2] + 1;
1220 *outnumvertices = outvertices;
1221 return outtriangles;
1224 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)
1227 int outtriangles = 0, outvertices = 0;
1229 const float *vertex;
1230 float ratio, direction[3], projectvector[3];
1233 if (projectdirection)
1234 VectorScale(projectdirection, projectdistance, projectvector);
1236 VectorClear(projectvector);
1238 for (i = 0;i < numshadowmarktris;i++)
1240 int remappedelement[3];
1242 const int *neighbortriangle;
1244 markindex = shadowmarktris[i] * 3;
1245 neighbortriangle = inneighbor3i + markindex;
1246 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1247 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1248 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1249 if (side[0] + side[1] + side[2] == 0)
1253 element = inelement3i + markindex;
1255 // create the vertices
1256 for (j = 0;j < 3;j++)
1258 if (side[j] + side[j+1] == 0)
1261 if (vertexupdate[k] != vertexupdatenum)
1263 vertexupdate[k] = vertexupdatenum;
1264 vertexremap[k] = outvertices;
1265 vertex = invertex3f + k * 3;
1266 VectorCopy(vertex, outvertex3f);
1267 if (projectdirection)
1269 // project one copy of the vertex according to projectvector
1270 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1274 // project one copy of the vertex to the sphere radius of the light
1275 // (FIXME: would projecting it to the light box be better?)
1276 VectorSubtract(vertex, projectorigin, direction);
1277 ratio = projectdistance / VectorLength(direction);
1278 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1285 // output the sides (facing outward from this triangle)
1288 remappedelement[0] = vertexremap[element[0]];
1289 remappedelement[1] = vertexremap[element[1]];
1290 outelement3i[0] = remappedelement[1];
1291 outelement3i[1] = remappedelement[0];
1292 outelement3i[2] = remappedelement[0] + 1;
1293 outelement3i[3] = remappedelement[1];
1294 outelement3i[4] = remappedelement[0] + 1;
1295 outelement3i[5] = remappedelement[1] + 1;
1302 remappedelement[1] = vertexremap[element[1]];
1303 remappedelement[2] = vertexremap[element[2]];
1304 outelement3i[0] = remappedelement[2];
1305 outelement3i[1] = remappedelement[1];
1306 outelement3i[2] = remappedelement[1] + 1;
1307 outelement3i[3] = remappedelement[2];
1308 outelement3i[4] = remappedelement[1] + 1;
1309 outelement3i[5] = remappedelement[2] + 1;
1316 remappedelement[0] = vertexremap[element[0]];
1317 remappedelement[2] = vertexremap[element[2]];
1318 outelement3i[0] = remappedelement[0];
1319 outelement3i[1] = remappedelement[2];
1320 outelement3i[2] = remappedelement[2] + 1;
1321 outelement3i[3] = remappedelement[0];
1322 outelement3i[4] = remappedelement[2] + 1;
1323 outelement3i[5] = remappedelement[0] + 1;
1330 *outnumvertices = outvertices;
1331 return outtriangles;
1334 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)
1340 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1342 tend = firsttriangle + numtris;
1343 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1345 // surface box entirely inside light box, no box cull
1346 if (projectdirection)
1348 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1350 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1351 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1352 shadowmarklist[numshadowmark++] = t;
1357 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1358 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1359 shadowmarklist[numshadowmark++] = t;
1364 // surface box not entirely inside light box, cull each triangle
1365 if (projectdirection)
1367 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1369 v[0] = invertex3f + e[0] * 3;
1370 v[1] = invertex3f + e[1] * 3;
1371 v[2] = invertex3f + e[2] * 3;
1372 TriangleNormal(v[0], v[1], v[2], normal);
1373 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1374 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1375 shadowmarklist[numshadowmark++] = t;
1380 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1382 v[0] = invertex3f + e[0] * 3;
1383 v[1] = invertex3f + e[1] * 3;
1384 v[2] = invertex3f + e[2] * 3;
1385 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1386 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1387 shadowmarklist[numshadowmark++] = t;
1393 static qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1398 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1400 // check if the shadow volume intersects the near plane
1402 // a ray between the eye and light origin may intersect the caster,
1403 // indicating that the shadow may touch the eye location, however we must
1404 // test the near plane (a polygon), not merely the eye location, so it is
1405 // easiest to enlarge the caster bounding shape slightly for this.
1411 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)
1413 int i, tris, outverts;
1414 if (projectdistance < 0.1)
1416 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1419 if (!numverts || !nummarktris)
1421 // make sure shadowelements is big enough for this volume
1422 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1423 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1425 if (maxvertexupdate < numverts)
1427 maxvertexupdate = numverts;
1429 Mem_Free(vertexupdate);
1431 Mem_Free(vertexremap);
1432 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1433 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1434 vertexupdatenum = 0;
1437 if (vertexupdatenum == 0)
1439 vertexupdatenum = 1;
1440 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1441 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1444 for (i = 0;i < nummarktris;i++)
1445 shadowmark[marktris[i]] = shadowmarkcount;
1447 if (r_shadow_compilingrtlight)
1449 // if we're compiling an rtlight, capture the mesh
1450 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1451 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1452 tris = R_Shadow_ConstructShadowVolume_ZFail(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_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1455 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1457 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1458 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1459 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1463 // decide which type of shadow to generate and set stencil mode
1464 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1465 // generate the sides or a solid volume, depending on type
1466 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1467 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1469 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1470 r_refdef.stats[r_stat_lights_dynamicshadowtriangles] += tris;
1471 r_refdef.stats[r_stat_lights_shadowtriangles] += tris;
1472 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1474 // increment stencil if frontface is infront of depthbuffer
1475 GL_CullFace(r_refdef.view.cullface_front);
1476 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1477 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1478 // decrement stencil if backface is infront of depthbuffer
1479 GL_CullFace(r_refdef.view.cullface_back);
1480 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1482 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1484 // decrement stencil if backface is behind depthbuffer
1485 GL_CullFace(r_refdef.view.cullface_front);
1486 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1487 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1488 // increment stencil if frontface is behind depthbuffer
1489 GL_CullFace(r_refdef.view.cullface_back);
1490 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1492 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1493 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1497 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1499 // p1, p2, p3 are in the cubemap's local coordinate system
1500 // bias = border/(size - border)
1503 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1504 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1505 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1506 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1508 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1509 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1510 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1511 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1513 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1514 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1515 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1517 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1518 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1519 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1520 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1522 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1523 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1524 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1525 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1527 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1528 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1529 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1531 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1532 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1533 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1534 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1536 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1537 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1538 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1539 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1541 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1542 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1543 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1548 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1550 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1551 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1554 VectorSubtract(maxs, mins, radius);
1555 VectorScale(radius, 0.5f, radius);
1556 VectorAdd(mins, radius, center);
1557 Matrix4x4_Transform(worldtolight, center, lightcenter);
1558 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1559 VectorSubtract(lightcenter, lightradius, pmin);
1560 VectorAdd(lightcenter, lightradius, pmax);
1562 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1563 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1564 if(ap1 > bias*an1 && ap2 > bias*an2)
1566 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1567 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1568 if(an1 > bias*ap1 && an2 > bias*ap2)
1570 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1571 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1573 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1574 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1575 if(ap1 > bias*an1 && ap2 > bias*an2)
1577 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1578 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1579 if(an1 > bias*ap1 && an2 > bias*ap2)
1581 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1582 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1584 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1585 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1586 if(ap1 > bias*an1 && ap2 > bias*an2)
1588 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1589 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1590 if(an1 > bias*ap1 && an2 > bias*ap2)
1592 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1593 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1598 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1600 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1602 // p is in the cubemap's local coordinate system
1603 // bias = border/(size - border)
1604 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1605 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1606 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1608 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1609 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1610 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1611 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1612 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1613 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1617 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1621 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1622 float scale = (size - 2*border)/size, len;
1623 float bias = border / (float)(size - border), dp, dn, ap, an;
1624 // check if cone enclosing side would cross frustum plane
1625 scale = 2 / (scale*scale + 2);
1626 Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
1627 for (i = 0;i < 5;i++)
1629 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
1631 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1632 len = scale*VectorLength2(n);
1633 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1634 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1635 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1637 if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1639 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1640 len = scale*VectorLength2(n);
1641 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1642 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1643 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1645 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1646 // check if frustum corners/origin cross plane sides
1648 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1649 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1650 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1651 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1652 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1653 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1654 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1655 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1656 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1657 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1658 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1659 for (i = 0;i < 4;i++)
1661 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1662 VectorSubtract(n, p, n);
1663 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1664 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1665 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1666 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1667 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1668 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1669 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1670 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1671 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1674 // finite version, assumes corners are a finite distance from origin dependent on far plane
1675 for (i = 0;i < 5;i++)
1677 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1678 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1679 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1680 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1681 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1682 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1683 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1684 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1685 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1686 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1689 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1692 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)
1700 int mask, surfacemask = 0;
1701 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1703 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1704 tend = firsttriangle + numtris;
1705 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1707 // surface box entirely inside light box, no box cull
1708 if (projectdirection)
1710 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1712 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1713 TriangleNormal(v[0], v[1], v[2], normal);
1714 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1716 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1717 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1718 surfacemask |= mask;
1721 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;
1722 shadowsides[numshadowsides] = mask;
1723 shadowsideslist[numshadowsides++] = t;
1730 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1732 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1733 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1735 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1736 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1737 surfacemask |= mask;
1740 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;
1741 shadowsides[numshadowsides] = mask;
1742 shadowsideslist[numshadowsides++] = t;
1750 // surface box not entirely inside light box, cull each triangle
1751 if (projectdirection)
1753 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1755 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1756 TriangleNormal(v[0], v[1], v[2], normal);
1757 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1758 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1760 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1761 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1762 surfacemask |= mask;
1765 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1766 shadowsides[numshadowsides] = mask;
1767 shadowsideslist[numshadowsides++] = t;
1774 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1776 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1777 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1778 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1780 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1781 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1782 surfacemask |= mask;
1785 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;
1786 shadowsides[numshadowsides] = mask;
1787 shadowsideslist[numshadowsides++] = t;
1796 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)
1798 int i, j, outtriangles = 0;
1799 int *outelement3i[6];
1800 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1802 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1803 // make sure shadowelements is big enough for this mesh
1804 if (maxshadowtriangles < outtriangles)
1805 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1807 // compute the offset and size of the separate index lists for each cubemap side
1809 for (i = 0;i < 6;i++)
1811 outelement3i[i] = shadowelements + outtriangles * 3;
1812 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1813 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1814 outtriangles += sidetotals[i];
1817 // gather up the (sparse) triangles into separate index lists for each cubemap side
1818 for (i = 0;i < numsidetris;i++)
1820 const int *element = elements + sidetris[i] * 3;
1821 for (j = 0;j < 6;j++)
1823 if (sides[i] & (1 << j))
1825 outelement3i[j][0] = element[0];
1826 outelement3i[j][1] = element[1];
1827 outelement3i[j][2] = element[2];
1828 outelement3i[j] += 3;
1833 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1836 static void R_Shadow_MakeTextures_MakeCorona(void)
1840 unsigned char pixels[32][32][4];
1841 for (y = 0;y < 32;y++)
1843 dy = (y - 15.5f) * (1.0f / 16.0f);
1844 for (x = 0;x < 32;x++)
1846 dx = (x - 15.5f) * (1.0f / 16.0f);
1847 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1848 a = bound(0, a, 255);
1849 pixels[y][x][0] = a;
1850 pixels[y][x][1] = a;
1851 pixels[y][x][2] = a;
1852 pixels[y][x][3] = 255;
1855 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, false);
1858 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1860 float dist = sqrt(x*x+y*y+z*z);
1861 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1862 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1863 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1866 static void R_Shadow_MakeTextures(void)
1869 float intensity, dist;
1871 R_Shadow_FreeShadowMaps();
1872 R_FreeTexturePool(&r_shadow_texturepool);
1873 r_shadow_texturepool = R_AllocTexturePool();
1874 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1875 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1876 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1877 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1878 for (x = 0;x <= ATTENTABLESIZE;x++)
1880 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1881 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1882 r_shadow_attentable[x] = bound(0, intensity, 1);
1884 // 1D gradient texture
1885 for (x = 0;x < ATTEN1DSIZE;x++)
1886 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1887 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1888 // 2D circle texture
1889 for (y = 0;y < ATTEN2DSIZE;y++)
1890 for (x = 0;x < ATTEN2DSIZE;x++)
1891 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);
1892 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1893 // 3D sphere texture
1894 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1896 for (z = 0;z < ATTEN3DSIZE;z++)
1897 for (y = 0;y < ATTEN3DSIZE;y++)
1898 for (x = 0;x < ATTEN3DSIZE;x++)
1899 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));
1900 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);
1903 r_shadow_attenuation3dtexture = NULL;
1906 R_Shadow_MakeTextures_MakeCorona();
1908 // Editor light sprites
1909 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1926 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1927 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1944 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1945 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1962 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1963 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1980 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1981 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1998 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1999 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
2016 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
2019 void R_Shadow_ValidateCvars(void)
2021 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
2022 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
2023 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
2024 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
2025 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
2026 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
2029 void R_Shadow_RenderMode_Begin(void)
2035 R_Shadow_ValidateCvars();
2037 if (!r_shadow_attenuation2dtexture
2038 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
2039 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
2040 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
2041 R_Shadow_MakeTextures();
2044 R_Mesh_ResetTextureState();
2045 GL_BlendFunc(GL_ONE, GL_ZERO);
2046 GL_DepthRange(0, 1);
2047 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
2049 GL_DepthMask(false);
2050 GL_Color(0, 0, 0, 1);
2051 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2053 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2055 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
2057 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
2058 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
2060 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
2062 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
2063 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
2067 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
2068 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
2071 switch(vid.renderpath)
2073 case RENDERPATH_GL20:
2074 case RENDERPATH_D3D9:
2075 case RENDERPATH_D3D10:
2076 case RENDERPATH_D3D11:
2077 case RENDERPATH_SOFT:
2078 case RENDERPATH_GLES2:
2079 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
2081 case RENDERPATH_GL11:
2082 case RENDERPATH_GL13:
2083 case RENDERPATH_GLES1:
2084 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
2085 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
2086 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
2087 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
2088 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
2089 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
2091 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
2097 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
2098 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
2099 r_shadow_drawbuffer = drawbuffer;
2100 r_shadow_readbuffer = readbuffer;
2102 r_shadow_cullface_front = r_refdef.view.cullface_front;
2103 r_shadow_cullface_back = r_refdef.view.cullface_back;
2106 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
2108 rsurface.rtlight = rtlight;
2111 void R_Shadow_RenderMode_Reset(void)
2113 R_Mesh_ResetTextureState();
2114 R_Mesh_SetRenderTargets(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture, NULL, NULL, NULL);
2115 R_SetViewport(&r_refdef.view.viewport);
2116 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
2117 GL_DepthRange(0, 1);
2119 GL_DepthMask(false);
2120 GL_DepthFunc(GL_LEQUAL);
2121 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2122 r_refdef.view.cullface_front = r_shadow_cullface_front;
2123 r_refdef.view.cullface_back = r_shadow_cullface_back;
2124 GL_CullFace(r_refdef.view.cullface_back);
2125 GL_Color(1, 1, 1, 1);
2126 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2127 GL_BlendFunc(GL_ONE, GL_ZERO);
2128 R_SetupShader_Generic_NoTexture(false, false);
2129 r_shadow_usingshadowmap2d = false;
2130 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2133 void R_Shadow_ClearStencil(void)
2135 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2136 r_refdef.stats[r_stat_lights_clears]++;
2139 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2141 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2142 if (r_shadow_rendermode == mode)
2144 R_Shadow_RenderMode_Reset();
2145 GL_DepthFunc(GL_LESS);
2146 GL_ColorMask(0, 0, 0, 0);
2147 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2148 GL_CullFace(GL_NONE);
2149 R_SetupShader_DepthOrShadow(false, false, false); // FIXME test if we have a skeletal model?
2150 r_shadow_rendermode = mode;
2155 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2156 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2157 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2159 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2160 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2161 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2166 static void R_Shadow_MakeVSDCT(void)
2168 // maps to a 2x3 texture rectangle with normalized coordinates
2173 // stores abs(dir.xy), offset.xy/2.5
2174 unsigned char data[4*6] =
2176 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2177 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2178 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2179 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2180 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2181 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2183 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2186 static void R_Shadow_MakeShadowMap(int texturesize)
2188 switch (r_shadow_shadowmode)
2190 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2191 if (r_shadow_shadowmap2ddepthtexture) return;
2192 if (r_fb.usedepthtextures)
2194 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);
2195 r_shadow_shadowmap2ddepthbuffer = NULL;
2196 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2200 r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", texturesize, texturesize, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2201 r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
2202 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2210 void R_Shadow_ClearShadowMapTexture(void)
2212 r_viewport_t viewport;
2213 float clearcolor[4];
2215 // if they don't exist, create our textures now
2216 if (!r_shadow_shadowmap2ddepthtexture)
2217 R_Shadow_MakeShadowMap(r_shadow_shadowmaptexturesize);
2218 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2219 R_Shadow_MakeVSDCT();
2221 // we're setting up to render shadowmaps, so change rendermode
2222 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2224 R_Mesh_ResetTextureState();
2225 R_Shadow_RenderMode_Reset();
2226 if (r_shadow_shadowmap2ddepthbuffer)
2227 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2229 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2230 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2231 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2235 // we have to set a viewport to clear anything in some renderpaths (D3D)
2236 R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize, 0, 0, 1.0, 1.0, 0.001f, 1.0f, NULL);
2237 R_SetViewport(&viewport);
2238 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2239 if (r_shadow_shadowmap2ddepthbuffer)
2240 GL_ColorMask(1, 1, 1, 1);
2242 GL_ColorMask(0, 0, 0, 0);
2243 switch (vid.renderpath)
2245 case RENDERPATH_GL11:
2246 case RENDERPATH_GL13:
2247 case RENDERPATH_GL20:
2248 case RENDERPATH_SOFT:
2249 case RENDERPATH_GLES1:
2250 case RENDERPATH_GLES2:
2251 GL_CullFace(r_refdef.view.cullface_back);
2253 case RENDERPATH_D3D9:
2254 case RENDERPATH_D3D10:
2255 case RENDERPATH_D3D11:
2256 // we invert the cull mode because we flip the projection matrix
2257 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2258 GL_CullFace(r_refdef.view.cullface_front);
2261 Vector4Set(clearcolor, 1, 1, 1, 1);
2262 if (r_shadow_shadowmap2ddepthbuffer)
2263 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2265 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2268 static void R_Shadow_SetShadowmapParametersForLight(qboolean noselfshadowpass)
2270 int size = rsurface.rtlight->shadowmapatlassidesize;
2271 float nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2272 float farclip = 1.0f;
2273 float bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2274 r_shadow_lightshadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
2275 r_shadow_lightshadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
2276 r_shadow_lightshadowmap_texturescale[2] = rsurface.rtlight->shadowmapatlasposition[0] + (noselfshadowpass ? size * 2 : 0);
2277 r_shadow_lightshadowmap_texturescale[3] = rsurface.rtlight->shadowmapatlasposition[1];
2278 r_shadow_lightshadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2279 r_shadow_lightshadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2280 r_shadow_lightshadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2281 r_shadow_lightshadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2282 if (r_shadow_shadowmap2ddepthbuffer)
2284 // completely different meaning than in depthtexture approach
2285 r_shadow_lightshadowmap_parameters[1] = 0;
2286 r_shadow_lightshadowmap_parameters[3] = -bias;
2290 static void R_Shadow_RenderMode_ShadowMap(int side, int size, int x, int y)
2292 float nearclip, farclip, bias;
2293 r_viewport_t viewport;
2295 float clearcolor[4];
2297 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_SHADOWMAP2D)
2299 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2301 R_Mesh_ResetTextureState();
2302 R_Shadow_RenderMode_Reset();
2303 if (r_shadow_shadowmap2ddepthbuffer)
2304 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2306 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2307 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2308 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2313 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2315 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2317 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
2318 R_SetViewport(&viewport);
2319 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2320 flipped = (side & 1) ^ (side >> 2);
2321 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2322 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2324 Vector4Set(clearcolor, 1,1,1,1);
2325 if (r_shadow_shadowmap2ddepthbuffer)
2326 GL_ColorMask(1,1,1,1);
2328 GL_ColorMask(0,0,0,0);
2329 switch(vid.renderpath)
2331 case RENDERPATH_GL11:
2332 case RENDERPATH_GL13:
2333 case RENDERPATH_GL20:
2334 case RENDERPATH_SOFT:
2335 case RENDERPATH_GLES1:
2336 case RENDERPATH_GLES2:
2337 GL_CullFace(r_refdef.view.cullface_back);
2339 case RENDERPATH_D3D9:
2340 case RENDERPATH_D3D10:
2341 case RENDERPATH_D3D11:
2342 // we invert the cull mode because we flip the projection matrix
2343 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2344 GL_CullFace(r_refdef.view.cullface_front);
2348 // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
2349 r_shadow_shadowmapside = side;
2352 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass)
2354 R_Mesh_ResetTextureState();
2357 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2358 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2359 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2360 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2363 R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
2364 R_Shadow_RenderMode_Reset();
2365 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2367 GL_DepthFunc(GL_EQUAL);
2368 // do global setup needed for the chosen lighting mode
2369 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2370 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2371 r_shadow_usingshadowmap2d = shadowmapping;
2372 r_shadow_rendermode = r_shadow_lightingrendermode;
2373 // only draw light where this geometry was already rendered AND the
2374 // stencil is 128 (values other than this mean shadow)
2376 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2378 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2381 static const unsigned short bboxelements[36] =
2391 static const float bboxpoints[8][3] =
2403 void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping)
2406 float vertex3f[8*3];
2407 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2408 // do global setup needed for the chosen lighting mode
2409 R_Shadow_RenderMode_Reset();
2410 r_shadow_rendermode = r_shadow_lightingrendermode;
2411 R_EntityMatrix(&identitymatrix);
2412 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2413 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2414 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
2415 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2417 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
2419 r_shadow_usingshadowmap2d = shadowmapping;
2421 // render the lighting
2422 R_SetupShader_DeferredLight(rsurface.rtlight);
2423 for (i = 0;i < 8;i++)
2424 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2425 GL_ColorMask(1,1,1,1);
2426 GL_DepthMask(false);
2427 GL_DepthRange(0, 1);
2428 GL_PolygonOffset(0, 0);
2430 GL_DepthFunc(GL_GREATER);
2431 GL_CullFace(r_refdef.view.cullface_back);
2432 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
2433 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2436 #define MAXBOUNCEGRIDSPLATSIZE 7
2437 #define MAXBOUNCEGRIDSPLATSIZE1 (MAXBOUNCEGRIDSPLATSIZE+1)
2439 // these are temporary data per-frame, sorted and performed in a more
2440 // cache-friendly order than the original photons
2441 typedef struct r_shadow_bouncegrid_splatpath_s
2447 vec_t splatintensity;
2448 vec_t splatsize_current;
2449 vec_t splatsize_perstep;
2450 int remainingsplats;
2452 r_shadow_bouncegrid_splatpath_t;
2454 static void R_Shadow_BounceGrid_AddSplatPath(vec3_t originalstart, vec3_t originalend, vec3_t color, vec_t distancetraveled)
2464 r_shadow_bouncegrid_splatpath_t *path;
2466 // cull paths that fail R_CullBox in dynamic mode
2467 if (!r_shadow_bouncegrid_state.settings.staticmode
2468 && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
2470 vec3_t cullmins, cullmaxs;
2471 cullmins[0] = min(originalstart[0], originalend[0]) - r_shadow_bouncegrid_state.settings.spacing[0];
2472 cullmins[1] = min(originalstart[1], originalend[1]) - r_shadow_bouncegrid_state.settings.spacing[1];
2473 cullmins[2] = min(originalstart[2], originalend[2]) - r_shadow_bouncegrid_state.settings.spacing[2];
2474 cullmaxs[0] = max(originalstart[0], originalend[0]) + r_shadow_bouncegrid_state.settings.spacing[0];
2475 cullmaxs[1] = max(originalstart[1], originalend[1]) + r_shadow_bouncegrid_state.settings.spacing[1];
2476 cullmaxs[2] = max(originalstart[2], originalend[2]) + r_shadow_bouncegrid_state.settings.spacing[2];
2477 if (R_CullBox(cullmins, cullmaxs))
2481 // if the light path is going upward, reverse it - we always draw down.
2482 if (originalend[2] < originalstart[2])
2484 VectorCopy(originalend, start);
2485 VectorCopy(originalstart, end);
2489 VectorCopy(originalstart, start);
2490 VectorCopy(originalend, end);
2493 // transform to texture pixels
2494 start[0] = (start[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2495 start[1] = (start[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2496 start[2] = (start[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2497 end[0] = (end[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2498 end[1] = (end[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2499 end[2] = (end[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2501 // check if we need to grow the splatpaths array
2502 if (r_shadow_bouncegrid_state.maxsplatpaths <= r_shadow_bouncegrid_state.numsplatpaths)
2504 // double the limit, this will persist from frame to frame so we don't
2505 // make the same mistake each time
2506 r_shadow_bouncegrid_state.maxsplatpaths *= 2;
2507 if (r_shadow_bouncegrid_state.maxsplatpaths < 16384)
2508 r_shadow_bouncegrid_state.maxsplatpaths = 16384;
2509 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);
2512 // divide a series of splats along the length using the maximum axis
2513 VectorSubtract(end, start, diff);
2514 // pick the best axis to trace along
2516 if (diff[1]*diff[1] > diff[bestaxis]*diff[bestaxis])
2518 if (diff[2]*diff[2] > diff[bestaxis]*diff[bestaxis])
2520 len = fabs(diff[bestaxis]);
2522 numsplats = (int)(floor(len + 0.5f));
2524 numsplats = bound(0, numsplats, 1024);
2526 VectorSubtract(originalstart, originalend, originaldir);
2527 VectorNormalize(originaldir);
2529 path = r_shadow_bouncegrid_state.splatpaths + r_shadow_bouncegrid_state.numsplatpaths++;
2530 VectorCopy(start, path->point);
2531 VectorScale(diff, ilen, path->step);
2532 VectorCopy(color, path->splatcolor);
2533 VectorCopy(originaldir, path->splatdir);
2534 path->splatsize_current = r_shadow_bouncegrid_state.settings.lightpathsize_initial + r_shadow_bouncegrid_state.settings.lightpathsize_conespread * distancetraveled * r_shadow_bouncegrid_state.ispacing[0];
2535 path->splatsize_perstep = r_shadow_bouncegrid_state.settings.lightpathsize_conespread;
2536 path->splatintensity = VectorLength(color);
2537 path->remainingsplats = numsplats;
2540 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
2542 qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
2549 // see if there are really any lights to render...
2550 if (enable && r_shadow_bouncegrid_static.integer)
2553 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2554 for (lightindex = 0;lightindex < range;lightindex++)
2556 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2557 if (!light || !(light->flags & flag))
2559 rtlight = &light->rtlight;
2560 // when static, we skip styled lights because they tend to change...
2561 if (rtlight->style > 0)
2563 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
2564 if (!VectorLength2(lightcolor))
2574 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
2576 qboolean s = r_shadow_bouncegrid_static.integer != 0;
2577 float spacing = bound(1.0f, s ? r_shadow_bouncegrid_static_spacing.value : r_shadow_bouncegrid_dynamic_spacing.value, 1024.0f);
2578 float quality = bound(0.0001f, (s ? r_shadow_bouncegrid_static_quality.value : r_shadow_bouncegrid_dynamic_quality.value), 1024.0f);
2579 float bounceminimumintensity = s ? r_shadow_bouncegrid_static_bounceminimumintensity.value : r_shadow_bouncegrid_dynamic_bounceminimumintensity.value;
2581 // prevent any garbage in alignment padded areas as we'll be using memcmp
2582 memset(settings, 0, sizeof(*settings));
2584 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
2585 settings->staticmode = s;
2586 settings->blur = r_shadow_bouncegrid_blur.integer != 0;
2587 settings->floatcolors = bound(0, r_shadow_bouncegrid_floatcolors.integer, 2);
2588 settings->lightpathsize_initial = bound(0.0f, r_shadow_bouncegrid_lightpathsize_initial.value, 1024.0f);
2589 settings->lightpathsize_conespread = bound(0.0f, r_shadow_bouncegrid_lightpathsize_conespread.value, 1024.0f);
2590 settings->bounceanglediffuse = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
2591 settings->directionalshading = (s ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_dynamic_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
2592 settings->dlightparticlemultiplier = s ? 0 : r_shadow_bouncegrid_dynamic_dlightparticlemultiplier.value;
2593 settings->hitmodels = s ? false : r_shadow_bouncegrid_dynamic_hitmodels.integer != 0;
2594 settings->includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
2595 settings->lightradiusscale = (s ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_dynamic_lightradiusscale.value);
2596 settings->maxbounce = (s ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_dynamic_maxbounce.integer);
2597 settings->particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
2598 settings->particleintensity = r_shadow_bouncegrid_particleintensity.value * (settings->directionalshading ? 4.0f : 1.0f) * 16384 / (spacing * spacing) / 262144.0f;
2599 settings->maxphotons = s ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_dynamic_maxphotons.integer;
2600 settings->energyperphoton = spacing * spacing / quality;
2601 settings->spacing[0] = spacing;
2602 settings->spacing[1] = spacing;
2603 settings->spacing[2] = spacing;
2604 settings->rng_type = r_shadow_bouncegrid_rng_type.integer;
2605 settings->rng_seed = r_shadow_bouncegrid_rng_seed.integer;
2606 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
2607 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
2608 settings->normalizevectors = r_shadow_bouncegrid_normalizevectors.integer != 0;
2610 // bound the values for sanity
2611 settings->maxphotons = bound(1, settings->maxphotons, 25000000);
2612 settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
2613 settings->maxbounce = bound(0, settings->maxbounce, 16);
2614 settings->spacing[0] = bound(1, settings->spacing[0], 512);
2615 settings->spacing[1] = bound(1, settings->spacing[1], 512);
2616 settings->spacing[2] = bound(1, settings->spacing[2], 512);
2619 static void R_Shadow_BounceGrid_UpdateSpacing(void)
2630 r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
2632 // get the spacing values
2633 spacing[0] = settings->spacing[0];
2634 spacing[1] = settings->spacing[1];
2635 spacing[2] = settings->spacing[2];
2636 ispacing[0] = 1.0f / spacing[0];
2637 ispacing[1] = 1.0f / spacing[1];
2638 ispacing[2] = 1.0f / spacing[2];
2640 // calculate texture size enclosing entire world bounds at the spacing
2641 if (r_refdef.scene.worldmodel)
2645 qboolean bounds_set = false;
2649 // calculate bounds enclosing world lights as they should be noticably tighter
2650 // than the world bounds on maps with unlit monster containers (see e1m7 etc)
2651 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2652 for (lightindex = 0;lightindex < range;lightindex++)
2654 const vec_t *rtlmins, *rtlmaxs;
2656 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2660 rtlight = &light->rtlight;
2661 rtlmins = rtlight->cullmins;
2662 rtlmaxs = rtlight->cullmaxs;
2666 VectorCopy(rtlmins, mins);
2667 VectorCopy(rtlmaxs, maxs);
2672 mins[0] = min(mins[0], rtlmins[0]);
2673 mins[1] = min(mins[1], rtlmins[1]);
2674 mins[2] = min(mins[2], rtlmins[2]);
2675 maxs[0] = max(maxs[0], rtlmaxs[0]);
2676 maxs[1] = max(maxs[1], rtlmaxs[1]);
2677 maxs[2] = max(maxs[2], rtlmaxs[2]);
2681 // limit to no larger than the world bounds
2682 mins[0] = max(mins[0], r_refdef.scene.worldmodel->normalmins[0]);
2683 mins[1] = max(mins[1], r_refdef.scene.worldmodel->normalmins[1]);
2684 mins[2] = max(mins[2], r_refdef.scene.worldmodel->normalmins[2]);
2685 maxs[0] = min(maxs[0], r_refdef.scene.worldmodel->normalmaxs[0]);
2686 maxs[1] = min(maxs[1], r_refdef.scene.worldmodel->normalmaxs[1]);
2687 maxs[2] = min(maxs[2], r_refdef.scene.worldmodel->normalmaxs[2]);
2689 VectorMA(mins, -2.0f, spacing, mins);
2690 VectorMA(maxs, 2.0f, spacing, maxs);
2694 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
2695 VectorSet(maxs, 1048576.0f, 1048576.0f, 1048576.0f);
2697 VectorSubtract(maxs, mins, size);
2698 // now we can calculate the resolution we want
2699 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2700 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2701 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2702 // figure out the exact texture size (honoring power of 2 if required)
2703 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2704 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2705 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2706 if (vid.support.arb_texture_non_power_of_two)
2708 resolution[0] = c[0];
2709 resolution[1] = c[1];
2710 resolution[2] = c[2];
2714 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2715 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2716 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2718 size[0] = spacing[0] * resolution[0];
2719 size[1] = spacing[1] * resolution[1];
2720 size[2] = spacing[2] * resolution[2];
2722 // if dynamic we may or may not want to use the world bounds
2723 // if the dynamic size is smaller than the world bounds, use it instead
2724 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]))
2726 // we know the resolution we want
2727 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
2728 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
2729 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
2730 // now we can calculate the texture size (power of 2 if required)
2731 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2732 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2733 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2734 if (vid.support.arb_texture_non_power_of_two)
2736 resolution[0] = c[0];
2737 resolution[1] = c[1];
2738 resolution[2] = c[2];
2742 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2743 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2744 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2746 size[0] = spacing[0] * resolution[0];
2747 size[1] = spacing[1] * resolution[1];
2748 size[2] = spacing[2] * resolution[2];
2749 // center the rendering on the view
2750 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2751 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2752 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2755 // recalculate the maxs in case the resolution was not satisfactory
2756 VectorAdd(mins, size, maxs);
2758 // check if this changed the texture size
2759 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);
2760 r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
2761 VectorCopy(mins, r_shadow_bouncegrid_state.mins);
2762 VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
2763 VectorCopy(size, r_shadow_bouncegrid_state.size);
2764 VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
2765 VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
2766 VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
2768 // reallocate pixels for this update if needed...
2769 r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
2770 r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
2771 r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
2772 numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
2773 if (r_shadow_bouncegrid_state.numpixels != numpixels)
2775 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
2776 r_shadow_bouncegrid_state.highpixels = NULL;
2777 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2778 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2779 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2780 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2781 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2782 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2783 r_shadow_bouncegrid_state.numpixels = numpixels;
2786 // update the bouncegrid matrix to put it in the world properly
2787 memset(m, 0, sizeof(m));
2788 m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
2789 m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
2790 m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
2791 m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
2792 m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
2793 m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
2795 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
2798 // enumerate world rtlights and sum the overall amount of light in the world,
2799 // from that we can calculate a scaling factor to fairly distribute photons
2800 // to all the lights
2802 // this modifies rtlight->photoncolor and rtlight->photons
2803 static void R_Shadow_BounceGrid_AssignPhotons(r_shadow_bouncegrid_settings_t *settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
2805 float normalphotonscaling;
2806 float photonscaling;
2807 float photonintensity;
2808 float photoncount = 0.0f;
2809 float lightintensity;
2815 unsigned int lightindex;
2818 normalphotonscaling = 1.0f / max(0.0001f, settings->energyperphoton);
2819 for (lightindex = 0;lightindex < range2;lightindex++)
2821 if (lightindex < range)
2823 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2826 rtlight = &light->rtlight;
2827 VectorClear(rtlight->bouncegrid_photoncolor);
2828 rtlight->bouncegrid_photons = 0;
2829 rtlight->bouncegrid_hits = 0;
2830 rtlight->bouncegrid_traces = 0;
2831 rtlight->bouncegrid_effectiveradius = 0;
2832 if (!(light->flags & flag))
2834 if (settings->staticmode)
2836 // when static, we skip styled lights because they tend to change...
2837 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2840 else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
2845 rtlight = r_refdef.scene.lights[lightindex - range];
2846 VectorClear(rtlight->bouncegrid_photoncolor);
2847 rtlight->bouncegrid_photons = 0;
2848 rtlight->bouncegrid_hits = 0;
2849 rtlight->bouncegrid_traces = 0;
2850 rtlight->bouncegrid_effectiveradius = 0;
2852 // draw only visible lights (major speedup)
2853 radius = rtlight->radius * settings->lightradiusscale;
2854 cullmins[0] = rtlight->shadoworigin[0] - radius;
2855 cullmins[1] = rtlight->shadoworigin[1] - radius;
2856 cullmins[2] = rtlight->shadoworigin[2] - radius;
2857 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2858 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2859 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2860 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2861 if (!settings->staticmode)
2863 // skip if the expanded light box does not touch any visible leafs
2864 if (r_refdef.scene.worldmodel
2865 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2866 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2868 // skip if the expanded light box is not visible to traceline
2869 // note that PrepareLight already did this check but for a smaller box, so we
2870 // end up casting more traces per frame per light when using bouncegrid, which
2871 // is probably fine (and they use the same timer)
2872 if (r_shadow_culllights_trace.integer)
2874 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))
2875 rtlight->trace_timer = realtime;
2876 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
2879 // skip if expanded light box is offscreen
2880 if (R_CullBox(cullmins, cullmaxs))
2882 // skip if overall light intensity is zero
2883 if (w * VectorLength2(rtlight->color) == 0.0f)
2886 // a light that does not emit any light before style is applied, can be
2887 // skipped entirely (it may just be a corona)
2888 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2890 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2891 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2892 // skip lights that will emit no photons
2893 if (!VectorLength2(rtlight->bouncegrid_photoncolor))
2895 // shoot particles from this light
2896 // use a calculation for the number of particles that will not
2897 // vary with lightstyle, otherwise we get randomized particle
2898 // distribution, the seeded random is only consistent for a
2899 // consistent number of particles on this light...
2900 s = rtlight->radius;
2901 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2902 if (lightindex >= range)
2903 lightintensity *= settings->dlightparticlemultiplier;
2904 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2905 photoncount += rtlight->bouncegrid_photons;
2906 VectorScale(rtlight->bouncegrid_photoncolor, settings->particleintensity * settings->energyperphoton, rtlight->bouncegrid_photoncolor);
2907 // if the lightstyle happens to be off right now, we can skip actually
2908 // firing the photons, but we did have to count them in the total.
2909 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2910 // rtlight->bouncegrid_photons = 0;
2912 // the user provided an energyperphoton value which we try to use
2913 // if that results in too many photons to shoot this frame, then we cap it
2914 // which causes photons to appear/disappear from frame to frame, so we don't
2915 // like doing that in the typical case
2916 photonscaling = 1.0f;
2917 photonintensity = 1.0f;
2918 if (photoncount > settings->maxphotons)
2920 photonscaling = settings->maxphotons / photoncount;
2921 photonintensity = 1.0f / photonscaling;
2924 // modify the lights to reflect our computed scaling
2925 for (lightindex = 0; lightindex < range2; lightindex++)
2927 if (lightindex < range)
2929 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2932 rtlight = &light->rtlight;
2935 rtlight = r_refdef.scene.lights[lightindex - range];
2936 rtlight->bouncegrid_photons *= photonscaling;
2937 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2941 static int R_Shadow_BounceGrid_SplatPathCompare(const void *pa, const void *pb)
2943 r_shadow_bouncegrid_splatpath_t *a = (r_shadow_bouncegrid_splatpath_t *)pa;
2944 r_shadow_bouncegrid_splatpath_t *b = (r_shadow_bouncegrid_splatpath_t *)pb;
2945 // we only really care about sorting by Z
2946 if (a->point[2] < b->point[2])
2948 if (a->point[2] > b->point[2])
2953 static void R_Shadow_BounceGrid_ClearPixels(void)
2955 // clear the highpixels array we'll be accumulating into
2956 if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2957 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2958 if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2959 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2960 r_shadow_bouncegrid_state.highpixels_index = 0;
2961 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2962 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2965 static void R_Shadow_BounceGrid_PerformSplats(void)
2967 r_shadow_bouncegrid_splatpath_t *splatpaths = r_shadow_bouncegrid_state.splatpaths;
2968 r_shadow_bouncegrid_splatpath_t *splatpath;
2969 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2970 int numsplatpaths = r_shadow_bouncegrid_state.numsplatpaths;
2975 vec_t lightpathsize_current;
2976 vec_t lightpathsize_perstep;
2977 float splatcolor[32];
2979 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2980 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2984 // hush warnings about uninitialized data - pixelbands doesn't change but...
2985 memset(splatcolor, 0, sizeof(splatcolor));
2987 // we use this a lot, so get a local copy
2988 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2990 // sort the splats before we execute them, to reduce cache misses
2991 if (r_shadow_bouncegrid_sortlightpaths.integer)
2992 qsort(splatpaths, numsplatpaths, sizeof(*splatpaths), R_Shadow_BounceGrid_SplatPathCompare);
2994 splatpath = splatpaths;
2995 for (splatindex = 0;splatindex < numsplatpaths;splatindex++, splatpath++)
2997 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2998 // accumulate average shotcolor
2999 VectorCopy(splatpath->splatdir, dir);
3000 splatcolor[ 0] = splatpath->splatcolor[0];
3001 splatcolor[ 1] = splatpath->splatcolor[1];
3002 splatcolor[ 2] = splatpath->splatcolor[2];
3003 splatcolor[ 3] = 0.0f;
3006 // store bentnormal in case the shader has a use for it,
3007 // bentnormal is an intensity-weighted average of the directions,
3008 // and will be normalized on conversion to texture pixels.
3009 splatcolor[ 4] = dir[0] * splatpath->splatintensity;
3010 splatcolor[ 5] = dir[1] * splatpath->splatintensity;
3011 splatcolor[ 6] = dir[2] * splatpath->splatintensity;
3012 splatcolor[ 7] = splatpath->splatintensity;
3013 // for each color component (R, G, B) calculate the amount that a
3014 // direction contributes
3015 splatcolor[ 8] = splatcolor[0] * max(0.0f, dir[0]);
3016 splatcolor[ 9] = splatcolor[0] * max(0.0f, dir[1]);
3017 splatcolor[10] = splatcolor[0] * max(0.0f, dir[2]);
3018 splatcolor[11] = 0.0f;
3019 splatcolor[12] = splatcolor[1] * max(0.0f, dir[0]);
3020 splatcolor[13] = splatcolor[1] * max(0.0f, dir[1]);
3021 splatcolor[14] = splatcolor[1] * max(0.0f, dir[2]);
3022 splatcolor[15] = 0.0f;
3023 splatcolor[16] = splatcolor[2] * max(0.0f, dir[0]);
3024 splatcolor[17] = splatcolor[2] * max(0.0f, dir[1]);
3025 splatcolor[18] = splatcolor[2] * max(0.0f, dir[2]);
3026 splatcolor[19] = 0.0f;
3027 // and do the same for negative directions
3028 splatcolor[20] = splatcolor[0] * max(0.0f, -dir[0]);
3029 splatcolor[21] = splatcolor[0] * max(0.0f, -dir[1]);
3030 splatcolor[22] = splatcolor[0] * max(0.0f, -dir[2]);
3031 splatcolor[23] = 0.0f;
3032 splatcolor[24] = splatcolor[1] * max(0.0f, -dir[0]);
3033 splatcolor[25] = splatcolor[1] * max(0.0f, -dir[1]);
3034 splatcolor[26] = splatcolor[1] * max(0.0f, -dir[2]);
3035 splatcolor[27] = 0.0f;
3036 splatcolor[28] = splatcolor[2] * max(0.0f, -dir[0]);
3037 splatcolor[29] = splatcolor[2] * max(0.0f, -dir[1]);
3038 splatcolor[30] = splatcolor[2] * max(0.0f, -dir[2]);
3039 splatcolor[31] = 0.0f;
3041 // calculate the number of steps we need to traverse this distance
3042 VectorCopy(splatpath->point, steppos);
3043 VectorCopy(splatpath->step, stepdelta);
3044 numsteps = splatpath->remainingsplats;
3045 lightpathsize_current = splatpath->splatsize_current + 1.0f; // add 1.0 for the gradient fade around the sphere
3046 lightpathsize_perstep = splatpath->splatsize_perstep;
3047 for (step = 0;step < numsteps;step++)
3049 // the middle row/column/layer of each splat are full intensity
3052 if (lightpathsize_current > MAXBOUNCEGRIDSPLATSIZE)
3053 lightpathsize_current = MAXBOUNCEGRIDSPLATSIZE;
3054 splatmins[0] = max(1.0f, steppos[0] - lightpathsize_current * 0.5f);
3055 splatmins[1] = max(1.0f, steppos[1] - lightpathsize_current * 0.5f);
3056 splatmins[2] = max(1.0f, steppos[2] - lightpathsize_current * 0.5f);
3057 splatmaxs[0] = min(steppos[0] + lightpathsize_current * 0.5f, resolution[0] - 1.0f);
3058 splatmaxs[1] = min(steppos[1] + lightpathsize_current * 0.5f, resolution[1] - 1.0f);
3059 splatmaxs[2] = min(steppos[2] + lightpathsize_current * 0.5f, resolution[2] - 1.0f);
3060 if (splatmaxs[0] > splatmins[0] && splatmaxs[1] > splatmins[1] && splatmaxs[2] > splatmins[2])
3062 // it is within bounds... do the real work now
3063 int xi, yi, zi, band, row;
3067 float colorscale = 1.0f / lightpathsize_current;
3068 r_refdef.stats[r_stat_bouncegrid_splats]++;
3069 // accumulate light onto the pixels
3070 for (zi = (int)floor(splatmins[2]);zi < splatmaxs[2];zi++)
3072 pixelpos[2] = zi + 0.5f;
3073 for (yi = (int)floor(splatmins[1]); yi < splatmaxs[1]; yi++)
3075 pixelpos[1] = yi + 0.5f;
3076 row = (zi*resolution[1] + yi)*resolution[0];
3077 for (xi = (int)floor(splatmins[0]); xi < splatmaxs[0]; xi++)
3079 pixelpos[0] = xi + 0.5f;
3080 // simple radial antialiased sphere - linear gradient fade over 1 pixel from the edge
3081 w = lightpathsize_current - VectorDistance(pixelpos, steppos);
3087 p = highpixels + 4 * (row + xi);
3088 for (band = 0; band < pixelbands; band++, p += pixelsperband * 4)
3090 // add to the pixel color
3091 p[0] += splatcolor[band * 4 + 0] * w;
3092 p[1] += splatcolor[band * 4 + 1] * w;
3093 p[2] += splatcolor[band * 4 + 2] * w;
3094 p[3] += splatcolor[band * 4 + 3] * w;
3101 VectorAdd(steppos, stepdelta, steppos);
3102 lightpathsize_current += lightpathsize_perstep;
3107 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
3109 const float *inpixel;
3111 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
3114 unsigned int x, y, z;
3115 unsigned int resolution[3];
3116 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3117 for (pixelband = 0;pixelband < pixelbands;pixelband++)
3119 for (z = 1;z < resolution[2]-1;z++)
3121 for (y = 1;y < resolution[1]-1;y++)
3124 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3125 inpixel = inpixels + 4*index;
3126 outpixel = outpixels + 4*index;
3127 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
3129 outpixel[0] = (inpixel[0] + inpixel[ off] + inpixel[0-off]) * (1.0f / 3.0);
3130 outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
3131 outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
3132 outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
3139 static void R_Shadow_BounceGrid_BlurPixels(void)
3142 unsigned int resolution[3];
3144 if (!r_shadow_bouncegrid_state.settings.blur)
3147 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3149 pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3150 pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
3151 pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3152 pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
3155 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
3157 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
3159 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
3161 // toggle the state, highpixels now points to pixels[3] result
3162 r_shadow_bouncegrid_state.highpixels_index ^= 1;
3163 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3166 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
3168 int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
3169 unsigned char *pixelsbgra8 = NULL;
3170 unsigned char *pixelbgra8;
3171 unsigned short *pixelsrgba16f = NULL;
3172 unsigned short *pixelrgba16f;
3173 float *pixelsrgba32f = NULL;
3174 float *highpixels = r_shadow_bouncegrid_state.highpixels;
3177 unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
3178 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
3179 unsigned int pixelband;
3180 unsigned int x, y, z;
3181 unsigned int index, bandindex;
3182 unsigned int resolution[3];
3184 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3186 if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
3188 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3189 r_shadow_bouncegrid_state.texture = NULL;
3192 // if bentnormals exist, we need to normalize and bias them for the shader
3196 for (z = 0;z < resolution[2]-1;z++)
3198 for (y = 0;y < resolution[1]-1;y++)
3201 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3202 highpixel = highpixels + 4*index;
3203 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3205 // only convert pixels that were hit by photons
3206 if (highpixel[3] != 0.0f)
3207 VectorNormalize(highpixel);
3208 VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
3209 highpixel[pixelsperband * 4 + 3] = 1.0f;
3215 // start by clearing the pixels array - we won't be writing to all of it
3217 // then process only the pixels that have at least some color, skipping
3218 // the higher bands for speed on pixels that are black
3219 switch (floatcolors)
3222 if (r_shadow_bouncegrid_state.u8pixels == NULL)
3223 r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
3224 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
3225 for (pixelband = 0;pixelband < pixelbands;pixelband++)
3228 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
3230 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
3232 for (z = 1;z < resolution[2]-1;z++)
3234 for (y = 1;y < resolution[1]-1;y++)
3238 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3239 highpixel = highpixels + 4*index;
3240 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3242 // only convert pixels that were hit by photons
3243 if (VectorLength2(highpixel))
3245 // normalize the bentnormal now
3248 VectorNormalize(highpixel + pixelsperband * 4);
3249 highpixel[pixelsperband * 4 + 3] = 1.0f;
3251 // process all of the pixelbands for this pixel
3252 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3254 pixelbgra8 = pixelsbgra8 + 4*bandindex;
3255 bandpixel = highpixels + 4*bandindex;
3256 c[0] = (int)(bandpixel[0]*256.0f);
3257 c[1] = (int)(bandpixel[1]*256.0f);
3258 c[2] = (int)(bandpixel[2]*256.0f);
3259 c[3] = (int)(bandpixel[3]*256.0f);
3260 pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
3261 pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
3262 pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
3263 pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
3270 if (!r_shadow_bouncegrid_state.createtexture)
3271 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3273 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);
3276 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
3277 r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3278 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
3279 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3280 for (z = 1;z < resolution[2]-1;z++)
3282 for (y = 1;y < resolution[1]-1;y++)
3286 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3287 highpixel = highpixels + 4*index;
3288 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3290 // only convert pixels that were hit by photons
3291 if (VectorLength2(highpixel))
3293 // process all of the pixelbands for this pixel
3294 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3296 // time to have fun with IEEE 754 bit hacking...
3299 unsigned int raw[4];
3301 pixelrgba16f = pixelsrgba16f + 4*bandindex;
3302 bandpixel = highpixels + 4*bandindex;
3303 VectorCopy4(bandpixel, u.f);
3304 VectorCopy4(u.raw, c);
3305 // this math supports negative numbers, snaps denormals to zero
3306 //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
3307 //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
3308 //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
3309 //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
3310 // this math does not support negative
3311 pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
3312 pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
3313 pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
3314 pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
3321 if (!r_shadow_bouncegrid_state.createtexture)
3322 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3324 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);
3327 // our native format happens to match, so this is easy.
3328 pixelsrgba32f = highpixels;
3330 if (!r_shadow_bouncegrid_state.createtexture)
3331 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3333 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);
3337 r_shadow_bouncegrid_state.lastupdatetime = realtime;
3340 static void R_Shadow_BounceGrid_TracePhotons(r_shadow_bouncegrid_settings_t settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
3342 vec3_t bouncerandom[10];
3345 int hitsupercontentsmask;
3346 int skipsupercontentsmask;
3347 int skipmaterialflagsmask;
3351 float bounceminimumintensity2;
3353 //trace_t cliptrace2;
3354 //trace_t cliptrace3;
3355 unsigned int lightindex;
3357 randomseed_t randomseed;
3359 vec3_t baseshotcolor;
3365 vec_t distancetraveled;
3369 // compute a seed for the unstable random modes
3370 Math_RandomSeed_FromInts(&randomseed, 0, 0, 0, realtime * 1000.0);
3371 seed = realtime * 1000.0;
3373 r_shadow_bouncegrid_state.numsplatpaths = 0;
3375 // figure out what we want to interact with
3376 if (settings.hitmodels)
3377 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
3379 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
3380 skipsupercontentsmask = 0;
3381 skipmaterialflagsmask = MATERIALFLAGMASK_TRANSLUCENT;
3382 maxbounce = settings.maxbounce;
3384 for (lightindex = 0;lightindex < range2;lightindex++)
3386 if (lightindex < range)
3388 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3391 rtlight = &light->rtlight;
3394 rtlight = r_refdef.scene.lights[lightindex - range];
3395 // note that this code used to keep track of residual photons and
3396 // distribute them evenly to achieve exactly a desired photon count,
3397 // but that caused unwanted flickering in dynamic mode
3398 shootparticles = (int)floor(rtlight->bouncegrid_photons);
3399 // skip if we won't be shooting any photons
3400 if (!shootparticles)
3402 radius = rtlight->radius * settings.lightradiusscale;
3403 //s = settings.particleintensity / shootparticles;
3404 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
3405 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
3406 if (VectorLength2(baseshotcolor) <= 0.0f)
3408 r_refdef.stats[r_stat_bouncegrid_lights]++;
3409 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
3410 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
3411 bounceminimumintensity2 = VectorLength(baseshotcolor) * settings.bounceminimumintensity2;
3413 // for seeded random we start the RNG with the position of the light
3414 if (settings.rng_seed >= 0)
3422 u.f[0] = rtlight->shadoworigin[0];
3423 u.f[1] = rtlight->shadoworigin[1];
3424 u.f[2] = rtlight->shadoworigin[2];
3426 switch (settings.rng_type)
3430 // we have to shift the seed provided by the user because the result must be odd
3431 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3] ^ (settings.rng_seed << 1));
3434 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3] ^ settings.rng_seed;
3439 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
3441 VectorCopy(baseshotcolor, shotcolor);
3442 VectorCopy(rtlight->shadoworigin, clipstart);
3443 switch (settings.rng_type)
3447 VectorLehmerRandom(&randomseed, clipend);
3448 if (settings.bounceanglediffuse)
3450 // we want random to be stable, so we still have to do all the random we would have done
3451 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3452 VectorLehmerRandom(&randomseed, bouncerandom[bouncecount]);
3456 VectorCheeseRandom(seed, clipend);
3457 if (settings.bounceanglediffuse)
3459 // we want random to be stable, so we still have to do all the random we would have done
3460 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3461 VectorCheeseRandom(seed, bouncerandom[bouncecount]);
3466 // we want a uniform distribution spherically, not merely within the sphere
3467 if (settings.normalizevectors)
3468 VectorNormalize(clipend);
3470 VectorMA(clipstart, radius, clipend, clipend);
3471 distancetraveled = 0.0f;
3472 for (bouncecount = 0;;bouncecount++)
3474 r_refdef.stats[r_stat_bouncegrid_traces]++;
3475 rtlight->bouncegrid_traces++;
3476 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
3477 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
3478 if (settings.staticmode || settings.rng_seed < 0)
3480 // static mode fires a LOT of rays but none of them are identical, so they are not cached
3481 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
3482 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);
3486 // dynamic mode fires many rays and most will match the cache from the previous frame
3487 cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
3489 if (bouncecount > 0 || settings.includedirectlighting)
3492 VectorCopy(cliptrace.endpos, hitpos);
3493 R_Shadow_BounceGrid_AddSplatPath(clipstart, hitpos, shotcolor, distancetraveled);
3495 distancetraveled += VectorDistance(clipstart, cliptrace.endpos);
3496 s = VectorDistance(rtlight->shadoworigin, cliptrace.endpos);
3497 if (rtlight->bouncegrid_effectiveradius < s)
3498 rtlight->bouncegrid_effectiveradius = s;
3499 if (cliptrace.fraction >= 1.0f)
3501 r_refdef.stats[r_stat_bouncegrid_hits]++;
3502 rtlight->bouncegrid_hits++;
3503 if (bouncecount >= maxbounce)
3505 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
3506 // also clamp the resulting color to never add energy, even if the user requests extreme values
3507 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
3508 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
3510 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
3511 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
3512 surfcolor[0] = min(surfcolor[0], 1.0f);
3513 surfcolor[1] = min(surfcolor[1], 1.0f);
3514 surfcolor[2] = min(surfcolor[2], 1.0f);
3515 VectorMultiply(shotcolor, surfcolor, shotcolor);
3516 if (VectorLength2(shotcolor) <= bounceminimumintensity2)
3518 r_refdef.stats[r_stat_bouncegrid_bounces]++;
3519 if (settings.bounceanglediffuse)
3521 // random direction, primarily along plane normal
3522 s = VectorDistance(cliptrace.endpos, clipend);
3523 VectorMA(cliptrace.plane.normal, 0.95f, bouncerandom[bouncecount], clipend);
3524 VectorNormalize(clipend);
3525 VectorScale(clipend, s, clipend);
3529 // reflect the remaining portion of the line across plane normal
3530 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
3531 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
3533 // calculate the new line start and end
3534 VectorCopy(cliptrace.endpos, clipstart);
3535 VectorAdd(clipstart, clipend, clipend);
3541 void R_Shadow_UpdateBounceGridTexture(void)
3543 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3544 r_shadow_bouncegrid_settings_t settings;
3545 qboolean enable = false;
3546 qboolean settingschanged;
3547 unsigned int range; // number of world lights
3548 unsigned int range1; // number of dynamic lights (or zero if disabled)
3549 unsigned int range2; // range+range1
3551 enable = R_Shadow_BounceGrid_CheckEnable(flag);
3553 R_Shadow_BounceGrid_GenerateSettings(&settings);
3555 // changing intensity does not require an update
3556 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
3558 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
3560 // when settings change, we free everything as it is just simpler that way.
3561 if (settingschanged || !enable)
3563 // not enabled, make sure we free anything we don't need anymore.
3564 if (r_shadow_bouncegrid_state.texture)
3566 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3567 r_shadow_bouncegrid_state.texture = NULL;
3569 r_shadow_bouncegrid_state.highpixels = NULL;
3570 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
3571 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
3572 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
3573 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
3574 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
3575 r_shadow_bouncegrid_state.maxsplatpaths = 0;
3576 r_shadow_bouncegrid_state.numpixels = 0;
3577 r_shadow_bouncegrid_state.directional = false;
3583 // if all the settings seem identical to the previous update, return
3584 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
3587 // store the new settings
3588 r_shadow_bouncegrid_state.settings = settings;
3590 R_Shadow_BounceGrid_UpdateSpacing();
3592 // get the range of light numbers we'll be looping over:
3593 // range = static lights
3594 // range1 = dynamic lights (optional)
3595 // range2 = range + range1
3596 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3597 range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
3598 range2 = range + range1;
3600 // calculate weighting factors for distributing photons among the lights
3601 R_Shadow_BounceGrid_AssignPhotons(&settings, range, range1, range2, flag);
3603 // trace the photons from lights and accumulate illumination
3604 R_Shadow_BounceGrid_TracePhotons(settings, range, range1, range2, flag);
3606 // clear the texture
3607 R_Shadow_BounceGrid_ClearPixels();
3609 // accumulate the light splatting into texture
3610 R_Shadow_BounceGrid_PerformSplats();
3612 // apply a mild blur filter to the texture
3613 R_Shadow_BounceGrid_BlurPixels();
3615 // convert the pixels to lower precision and upload the texture
3616 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
3618 // after we compute the static lighting we don't need to keep the highpixels array around
3619 if (settings.staticmode)
3621 r_shadow_bouncegrid_state.highpixels = NULL;
3622 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
3623 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
3624 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
3625 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
3626 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
3627 r_shadow_bouncegrid_state.maxsplatpaths = 0;
3631 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
3633 R_Shadow_RenderMode_Reset();
3634 GL_BlendFunc(GL_ONE, GL_ONE);
3635 GL_DepthRange(0, 1);
3636 GL_DepthTest(r_showshadowvolumes.integer < 2);
3637 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
3638 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
3639 GL_CullFace(GL_NONE);
3640 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
3643 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
3645 R_Shadow_RenderMode_Reset();
3646 GL_BlendFunc(GL_ONE, GL_ONE);
3647 GL_DepthRange(0, 1);
3648 GL_DepthTest(r_showlighting.integer < 2);
3649 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
3651 GL_DepthFunc(GL_EQUAL);
3652 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
3653 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
3656 void R_Shadow_RenderMode_End(void)
3658 R_Shadow_RenderMode_Reset();
3659 R_Shadow_RenderMode_ActiveLight(NULL);
3661 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3662 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3665 int bboxedges[12][2] =
3684 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
3686 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
3688 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
3689 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
3690 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
3691 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
3694 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
3695 return true; // invisible
3696 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
3697 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
3698 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
3699 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
3700 r_refdef.stats[r_stat_lights_scissored]++;
3704 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
3707 const float *vertex3f;
3708 const float *normal3f;
3710 float dist, dot, distintensity, shadeintensity, v[3], n[3];
3711 switch (r_shadow_rendermode)
3713 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3714 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3715 if (VectorLength2(diffusecolor) > 0)
3717 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)
3719 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3720 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3721 if ((dot = DotProduct(n, v)) < 0)
3723 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3724 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
3727 VectorCopy(ambientcolor, color4f);
3728 if (r_refdef.fogenabled)
3731 f = RSurf_FogVertex(vertex3f);
3732 VectorScale(color4f, f, color4f);
3739 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3741 VectorCopy(ambientcolor, color4f);
3742 if (r_refdef.fogenabled)
3745 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3746 f = RSurf_FogVertex(vertex3f);
3747 VectorScale(color4f + 4*i, f, color4f);
3753 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3754 if (VectorLength2(diffusecolor) > 0)
3756 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)
3758 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3759 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3761 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3762 if ((dot = DotProduct(n, v)) < 0)
3764 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3765 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3766 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3767 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3771 color4f[0] = ambientcolor[0] * distintensity;
3772 color4f[1] = ambientcolor[1] * distintensity;
3773 color4f[2] = ambientcolor[2] * distintensity;
3775 if (r_refdef.fogenabled)
3778 f = RSurf_FogVertex(vertex3f);
3779 VectorScale(color4f, f, color4f);
3783 VectorClear(color4f);
3789 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3791 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3792 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3794 color4f[0] = ambientcolor[0] * distintensity;
3795 color4f[1] = ambientcolor[1] * distintensity;
3796 color4f[2] = ambientcolor[2] * distintensity;
3797 if (r_refdef.fogenabled)
3800 f = RSurf_FogVertex(vertex3f);
3801 VectorScale(color4f, f, color4f);
3805 VectorClear(color4f);
3810 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3811 if (VectorLength2(diffusecolor) > 0)
3813 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)
3815 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3816 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3818 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3819 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3820 if ((dot = DotProduct(n, v)) < 0)
3822 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3823 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3824 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3825 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3829 color4f[0] = ambientcolor[0] * distintensity;
3830 color4f[1] = ambientcolor[1] * distintensity;
3831 color4f[2] = ambientcolor[2] * distintensity;
3833 if (r_refdef.fogenabled)
3836 f = RSurf_FogVertex(vertex3f);
3837 VectorScale(color4f, f, color4f);
3841 VectorClear(color4f);
3847 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3849 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3850 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3852 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3853 color4f[0] = ambientcolor[0] * distintensity;
3854 color4f[1] = ambientcolor[1] * distintensity;
3855 color4f[2] = ambientcolor[2] * distintensity;
3856 if (r_refdef.fogenabled)
3859 f = RSurf_FogVertex(vertex3f);
3860 VectorScale(color4f, f, color4f);
3864 VectorClear(color4f);
3874 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3876 // used to display how many times a surface is lit for level design purposes
3877 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3878 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3882 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])
3884 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3885 R_SetupShader_Surface(ambientcolor, diffusecolor, specularcolor, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
3889 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3896 int newnumtriangles;
3900 int maxtriangles = 1024;
3901 int newelements[1024*3];
3902 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3903 for (renders = 0;renders < 4;renders++)
3908 newnumtriangles = 0;
3910 // due to low fillrate on the cards this vertex lighting path is
3911 // designed for, we manually cull all triangles that do not
3912 // contain a lit vertex
3913 // this builds batches of triangles from multiple surfaces and
3914 // renders them at once
3915 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3917 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3919 if (newnumtriangles)
3921 newfirstvertex = min(newfirstvertex, e[0]);
3922 newlastvertex = max(newlastvertex, e[0]);
3926 newfirstvertex = e[0];
3927 newlastvertex = e[0];
3929 newfirstvertex = min(newfirstvertex, e[1]);
3930 newlastvertex = max(newlastvertex, e[1]);
3931 newfirstvertex = min(newfirstvertex, e[2]);
3932 newlastvertex = max(newlastvertex, e[2]);
3938 if (newnumtriangles >= maxtriangles)
3940 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3941 newnumtriangles = 0;
3947 if (newnumtriangles >= 1)
3949 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3952 // if we couldn't find any lit triangles, exit early
3955 // now reduce the intensity for the next overbright pass
3956 // we have to clamp to 0 here incase the drivers have improper
3957 // handling of negative colors
3958 // (some old drivers even have improper handling of >1 color)
3960 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3962 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3964 c[0] = max(0, c[0] - 1);
3965 c[1] = max(0, c[1] - 1);
3966 c[2] = max(0, c[2] - 1);
3978 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const float ambientcolor[3], const float diffusecolor[3])
3980 // OpenGL 1.1 path (anything)
3981 float ambientcolorbase[3], diffusecolorbase[3];
3982 float ambientcolorpants[3], diffusecolorpants[3];
3983 float ambientcolorshirt[3], diffusecolorshirt[3];
3984 const float *surfacepants = rsurface.texture->render_colormap_pants;
3985 const float *surfaceshirt = rsurface.texture->render_colormap_shirt;
3986 rtexture_t *basetexture = rsurface.texture->basetexture;
3987 rtexture_t *pantstexture = rsurface.texture->pantstexture;
3988 rtexture_t *shirttexture = rsurface.texture->shirttexture;
3989 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3990 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3991 VectorCopy(ambientcolor, ambientcolorbase);
3992 VectorCopy(diffusecolor, diffusecolorbase);
3993 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3994 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3995 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3996 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
3997 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (VectorLength2(diffusecolor) > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3998 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
3999 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4000 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
4001 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
4002 R_Mesh_TexBind(0, basetexture);
4003 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
4004 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
4005 switch(r_shadow_rendermode)
4007 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
4008 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
4009 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
4010 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
4011 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4013 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
4014 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
4015 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
4016 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
4017 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4019 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
4020 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
4021 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
4022 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
4023 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4025 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
4030 //R_Mesh_TexBind(0, basetexture);
4031 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
4034 R_Mesh_TexBind(0, pantstexture);
4035 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
4039 R_Mesh_TexBind(0, shirttexture);
4040 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
4044 extern cvar_t gl_lightmaps;
4045 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
4048 float ambientcolor[3], diffusecolor[3], specularcolor[3];
4049 VectorM(rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient, rsurface.texture->render_rtlight_diffuse, ambientcolor);
4050 VectorM(rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient), rsurface.texture->render_rtlight_diffuse, diffusecolor);
4051 VectorM(rsurface.rtlight->specularscale, rsurface.texture->render_rtlight_specular, specularcolor);
4052 if (!r_shadow_usenormalmap.integer)
4054 VectorMAM(1.0f, ambientcolor, 1.0f, diffusecolor, ambientcolor);
4055 VectorClear(diffusecolor);
4056 VectorClear(specularcolor);
4058 VectorMultiply(ambientcolor, rsurface.rtlight->currentcolor, ambientcolor);
4059 VectorMultiply(diffusecolor, rsurface.rtlight->currentcolor, diffusecolor);
4060 VectorMultiply(specularcolor, rsurface.rtlight->currentcolor, specularcolor);
4061 if (VectorLength2(ambientcolor) + VectorLength2(diffusecolor) + VectorLength2(specularcolor) < (1.0f / 1048576.0f))
4063 negated = (rsurface.rtlight->currentcolor[0] + rsurface.rtlight->currentcolor[1] + rsurface.rtlight->currentcolor[2] < 0) && vid.support.ext_blend_subtract;
4066 VectorNegate(ambientcolor, ambientcolor);
4067 VectorNegate(diffusecolor, diffusecolor);
4068 VectorNegate(specularcolor, specularcolor);
4069 GL_BlendEquationSubtract(true);
4071 RSurf_SetupDepthAndCulling();
4072 switch (r_shadow_rendermode)
4074 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
4075 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
4076 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
4078 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
4079 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, ambientcolor, diffusecolor, specularcolor);
4081 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
4082 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
4083 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
4084 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
4085 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, ambientcolor, diffusecolor);
4088 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
4092 GL_BlendEquationSubtract(false);
4095 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)
4097 matrix4x4_t tempmatrix = *matrix;
4098 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
4100 // if this light has been compiled before, free the associated data
4101 R_RTLight_Uncompile(rtlight);
4103 // clear it completely to avoid any lingering data
4104 memset(rtlight, 0, sizeof(*rtlight));
4106 // copy the properties
4107 rtlight->matrix_lighttoworld = tempmatrix;
4108 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
4109 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
4110 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
4111 VectorCopy(color, rtlight->color);
4112 rtlight->cubemapname[0] = 0;
4113 if (cubemapname && cubemapname[0])
4114 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
4115 rtlight->shadow = shadow;
4116 rtlight->corona = corona;
4117 rtlight->style = style;
4118 rtlight->isstatic = isstatic;
4119 rtlight->coronasizescale = coronasizescale;
4120 rtlight->ambientscale = ambientscale;
4121 rtlight->diffusescale = diffusescale;
4122 rtlight->specularscale = specularscale;
4123 rtlight->flags = flags;
4125 // compute derived data
4126 //rtlight->cullradius = rtlight->radius;
4127 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
4128 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
4129 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
4130 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
4131 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
4132 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
4133 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
4136 // compiles rtlight geometry
4137 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
4138 void R_RTLight_Compile(rtlight_t *rtlight)
4141 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
4142 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
4143 entity_render_t *ent = r_refdef.scene.worldentity;
4144 dp_model_t *model = r_refdef.scene.worldmodel;
4145 unsigned char *data;
4148 // compile the light
4149 rtlight->compiled = true;
4150 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
4151 rtlight->static_numleafs = 0;
4152 rtlight->static_numleafpvsbytes = 0;
4153 rtlight->static_leaflist = NULL;
4154 rtlight->static_leafpvs = NULL;
4155 rtlight->static_numsurfaces = 0;
4156 rtlight->static_surfacelist = NULL;
4157 rtlight->static_shadowmap_receivers = 0x3F;
4158 rtlight->static_shadowmap_casters = 0x3F;
4159 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
4160 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
4161 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
4162 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
4163 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
4164 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
4166 if (model && model->GetLightInfo)
4168 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
4169 r_shadow_compilingrtlight = rtlight;
4170 R_FrameData_SetMark();
4171 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);
4172 R_FrameData_ReturnToMark();
4173 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
4174 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
4175 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
4176 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
4177 rtlight->static_numsurfaces = numsurfaces;
4178 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
4179 rtlight->static_numleafs = numleafs;
4180 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
4181 rtlight->static_numleafpvsbytes = numleafpvsbytes;
4182 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
4183 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
4184 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
4185 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
4186 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
4187 if (rtlight->static_numsurfaces)
4188 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
4189 if (rtlight->static_numleafs)
4190 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
4191 if (rtlight->static_numleafpvsbytes)
4192 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
4193 if (rtlight->static_numshadowtrispvsbytes)
4194 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
4195 if (rtlight->static_numlighttrispvsbytes)
4196 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
4197 R_FrameData_SetMark();
4198 switch (rtlight->shadowmode)
4200 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4201 if (model->CompileShadowMap && rtlight->shadow)
4202 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
4205 if (model->CompileShadowVolume && rtlight->shadow)
4206 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
4209 R_FrameData_ReturnToMark();
4210 // now we're done compiling the rtlight
4211 r_shadow_compilingrtlight = NULL;
4215 // use smallest available cullradius - box radius or light radius
4216 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
4217 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
4219 shadowzpasstris = 0;
4220 if (rtlight->static_meshchain_shadow_zpass)
4221 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
4222 shadowzpasstris += mesh->numtriangles;
4224 shadowzfailtris = 0;
4225 if (rtlight->static_meshchain_shadow_zfail)
4226 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
4227 shadowzfailtris += mesh->numtriangles;
4230 if (rtlight->static_numlighttrispvsbytes)
4231 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
4232 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
4236 if (rtlight->static_numshadowtrispvsbytes)
4237 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
4238 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
4241 if (developer_extra.integer)
4242 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);
4245 void R_RTLight_Uncompile(rtlight_t *rtlight)
4247 if (rtlight->compiled)
4249 if (rtlight->static_meshchain_shadow_zpass)
4250 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
4251 rtlight->static_meshchain_shadow_zpass = NULL;
4252 if (rtlight->static_meshchain_shadow_zfail)
4253 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
4254 rtlight->static_meshchain_shadow_zfail = NULL;
4255 if (rtlight->static_meshchain_shadow_shadowmap)
4256 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
4257 rtlight->static_meshchain_shadow_shadowmap = NULL;
4258 // these allocations are grouped
4259 if (rtlight->static_surfacelist)
4260 Mem_Free(rtlight->static_surfacelist);
4261 rtlight->static_numleafs = 0;
4262 rtlight->static_numleafpvsbytes = 0;
4263 rtlight->static_leaflist = NULL;
4264 rtlight->static_leafpvs = NULL;
4265 rtlight->static_numsurfaces = 0;
4266 rtlight->static_surfacelist = NULL;
4267 rtlight->static_numshadowtrispvsbytes = 0;
4268 rtlight->static_shadowtrispvs = NULL;
4269 rtlight->static_numlighttrispvsbytes = 0;
4270 rtlight->static_lighttrispvs = NULL;
4271 rtlight->compiled = false;
4275 void R_Shadow_UncompileWorldLights(void)
4279 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4280 for (lightindex = 0;lightindex < range;lightindex++)
4282 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4285 R_RTLight_Uncompile(&light->rtlight);
4289 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
4293 // reset the count of frustum planes
4294 // see rtlight->cached_frustumplanes definition for how much this array
4296 rtlight->cached_numfrustumplanes = 0;
4298 if (r_trippy.integer)
4301 // haven't implemented a culling path for ortho rendering
4302 if (!r_refdef.view.useperspective)
4304 // check if the light is on screen and copy the 4 planes if it is
4305 for (i = 0;i < 4;i++)
4306 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4309 for (i = 0;i < 4;i++)
4310 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4315 // generate a deformed frustum that includes the light origin, this is
4316 // used to cull shadow casting surfaces that can not possibly cast a
4317 // shadow onto the visible light-receiving surfaces, which can be a
4320 // if the light origin is onscreen the result will be 4 planes exactly
4321 // if the light origin is offscreen on only one axis the result will
4322 // be exactly 5 planes (split-side case)
4323 // if the light origin is offscreen on two axes the result will be
4324 // exactly 4 planes (stretched corner case)
4325 for (i = 0;i < 4;i++)
4327 // quickly reject standard frustum planes that put the light
4328 // origin outside the frustum
4329 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4332 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4334 // if all the standard frustum planes were accepted, the light is onscreen
4335 // otherwise we need to generate some more planes below...
4336 if (rtlight->cached_numfrustumplanes < 4)
4338 // at least one of the stock frustum planes failed, so we need to
4339 // create one or two custom planes to enclose the light origin
4340 for (i = 0;i < 4;i++)
4342 // create a plane using the view origin and light origin, and a
4343 // single point from the frustum corner set
4344 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
4345 VectorNormalize(plane.normal);
4346 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
4347 // see if this plane is backwards and flip it if so
4348 for (j = 0;j < 4;j++)
4349 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4353 VectorNegate(plane.normal, plane.normal);
4355 // flipped plane, test again to see if it is now valid
4356 for (j = 0;j < 4;j++)
4357 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4359 // if the plane is still not valid, then it is dividing the
4360 // frustum and has to be rejected
4364 // we have created a valid plane, compute extra info
4365 PlaneClassify(&plane);
4367 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4369 // if we've found 5 frustum planes then we have constructed a
4370 // proper split-side case and do not need to keep searching for
4371 // planes to enclose the light origin
4372 if (rtlight->cached_numfrustumplanes == 5)
4380 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
4382 plane = rtlight->cached_frustumplanes[i];
4383 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));
4388 // now add the light-space box planes if the light box is rotated, as any
4389 // caster outside the oriented light box is irrelevant (even if it passed
4390 // the worldspace light box, which is axial)
4391 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
4393 for (i = 0;i < 6;i++)
4397 v[i >> 1] = (i & 1) ? -1 : 1;
4398 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
4399 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
4400 plane.dist = VectorNormalizeLength(plane.normal);
4401 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
4402 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4408 // add the world-space reduced box planes
4409 for (i = 0;i < 6;i++)
4411 VectorClear(plane.normal);
4412 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
4413 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
4414 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4423 // reduce all plane distances to tightly fit the rtlight cull box, which
4425 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4426 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4427 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4428 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4429 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4430 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4431 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4432 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4433 oldnum = rtlight->cached_numfrustumplanes;
4434 rtlight->cached_numfrustumplanes = 0;
4435 for (j = 0;j < oldnum;j++)
4437 // find the nearest point on the box to this plane
4438 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
4439 for (i = 1;i < 8;i++)
4441 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
4442 if (bestdist > dist)
4445 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);
4446 // if the nearest point is near or behind the plane, we want this
4447 // plane, otherwise the plane is useless as it won't cull anything
4448 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
4450 PlaneClassify(&rtlight->cached_frustumplanes[j]);
4451 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
4458 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
4462 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4464 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4467 GL_CullFace(GL_NONE);
4468 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
4469 for (;mesh;mesh = mesh->next)
4471 if (!mesh->sidetotals[r_shadow_shadowmapside])
4473 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
4474 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4475 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);
4479 else if (r_refdef.scene.worldentity->model)
4480 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);
4482 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4485 static void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
4487 qboolean zpass = false;
4490 int surfacelistindex;
4491 msurface_t *surface;
4493 // if triangle neighbors are disabled, shadowvolumes are disabled
4494 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
4497 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4499 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4502 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
4504 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
4505 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
4507 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
4508 for (;mesh;mesh = mesh->next)
4510 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->numtriangles;
4511 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4512 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
4514 // increment stencil if frontface is infront of depthbuffer
4515 GL_CullFace(r_refdef.view.cullface_back);
4516 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
4517 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);
4518 // decrement stencil if backface is infront of depthbuffer
4519 GL_CullFace(r_refdef.view.cullface_front);
4520 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
4522 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
4524 // decrement stencil if backface is behind depthbuffer
4525 GL_CullFace(r_refdef.view.cullface_front);
4526 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
4527 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);
4528 // increment stencil if frontface is behind depthbuffer
4529 GL_CullFace(r_refdef.view.cullface_back);
4530 R_SetStencil(true, 255, GL_KEEP, GL_INCR, 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);
4536 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
4538 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
4539 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
4540 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
4542 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
4543 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
4544 if (CHECKPVSBIT(trispvs, t))
4545 shadowmarklist[numshadowmark++] = t;
4547 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);
4549 else if (numsurfaces)
4551 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);
4554 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4557 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
4559 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
4560 vec_t relativeshadowradius;
4561 RSurf_ActiveModelEntity(ent, false, false, false);
4562 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
4563 // we need to re-init the shader for each entity because the matrix changed
4564 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
4565 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
4566 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
4567 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
4568 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
4569 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
4570 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
4571 switch (r_shadow_rendermode)
4573 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
4574 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4577 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4580 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4583 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
4585 // set up properties for rendering light onto this entity
4586 RSurf_ActiveModelEntity(ent, true, true, false);
4587 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
4588 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4589 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4590 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4593 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
4595 if (!r_refdef.scene.worldmodel->DrawLight)
4598 // set up properties for rendering light onto this entity
4599 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4600 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
4601 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4602 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4603 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4605 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
4607 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4610 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
4612 dp_model_t *model = ent->model;
4613 if (!model->DrawLight)
4616 R_Shadow_SetupEntityLight(ent);
4618 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
4620 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4623 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
4627 int numleafs, numsurfaces;
4628 int *leaflist, *surfacelist;
4629 unsigned char *leafpvs;
4630 unsigned char *shadowtrispvs;
4631 unsigned char *lighttrispvs;
4632 //unsigned char *surfacesides;
4633 int numlightentities;
4634 int numlightentities_noselfshadow;
4635 int numshadowentities;
4636 int numshadowentities_noselfshadow;
4637 // FIXME: bounds check lightentities and shadowentities, etc.
4638 static entity_render_t *lightentities[MAX_EDICTS];
4639 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
4640 static entity_render_t *shadowentities[MAX_EDICTS];
4641 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
4643 qboolean castshadows;
4645 rtlight->draw = false;
4646 rtlight->cached_numlightentities = 0;
4647 rtlight->cached_numlightentities_noselfshadow = 0;
4648 rtlight->cached_numshadowentities = 0;
4649 rtlight->cached_numshadowentities_noselfshadow = 0;
4650 rtlight->cached_numsurfaces = 0;
4651 rtlight->cached_lightentities = NULL;
4652 rtlight->cached_lightentities_noselfshadow = NULL;
4653 rtlight->cached_shadowentities = NULL;
4654 rtlight->cached_shadowentities_noselfshadow = NULL;
4655 rtlight->cached_shadowtrispvs = NULL;
4656 rtlight->cached_lighttrispvs = NULL;
4657 rtlight->cached_surfacelist = NULL;
4658 rtlight->shadowmapsidesize = 0;
4660 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
4661 // skip lights that are basically invisible (color 0 0 0)
4662 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
4664 // loading is done before visibility checks because loading should happen
4665 // all at once at the start of a level, not when it stalls gameplay.
4666 // (especially important to benchmarks)
4668 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
4670 if (rtlight->compiled)
4671 R_RTLight_Uncompile(rtlight);
4672 R_RTLight_Compile(rtlight);
4676 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
4678 // look up the light style value at this time
4679 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4680 VectorScale(rtlight->color, f, rtlight->currentcolor);
4682 if (rtlight->selected)
4684 f = 2 + sin(realtime * M_PI * 4.0);
4685 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
4689 // skip if lightstyle is currently off
4690 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
4693 // skip processing on corona-only lights
4697 // skip if the light box is not touching any visible leafs
4698 if (r_shadow_culllights_pvs.integer
4699 && r_refdef.scene.worldmodel
4700 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
4701 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, rtlight->cullmins, rtlight->cullmaxs))
4704 // skip if the light box is not visible to traceline
4705 if (r_shadow_culllights_trace.integer)
4707 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))
4708 rtlight->trace_timer = realtime;
4709 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
4713 // skip if the light box is off screen
4714 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
4717 // in the typical case this will be quickly replaced by GetLightInfo
4718 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
4719 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
4721 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4723 // 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
4724 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
4727 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
4729 // compiled light, world available and can receive realtime lighting
4730 // retrieve leaf information
4731 numleafs = rtlight->static_numleafs;
4732 leaflist = rtlight->static_leaflist;
4733 leafpvs = rtlight->static_leafpvs;
4734 numsurfaces = rtlight->static_numsurfaces;
4735 surfacelist = rtlight->static_surfacelist;
4736 //surfacesides = NULL;
4737 shadowtrispvs = rtlight->static_shadowtrispvs;
4738 lighttrispvs = rtlight->static_lighttrispvs;
4740 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4742 // dynamic light, world available and can receive realtime lighting
4743 // calculate lit surfaces and leafs
4744 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);
4745 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4746 leaflist = r_shadow_buffer_leaflist;
4747 leafpvs = r_shadow_buffer_leafpvs;
4748 surfacelist = r_shadow_buffer_surfacelist;
4749 //surfacesides = r_shadow_buffer_surfacesides;
4750 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4751 lighttrispvs = r_shadow_buffer_lighttrispvs;
4752 // if the reduced leaf bounds are offscreen, skip it
4753 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4764 //surfacesides = NULL;
4765 shadowtrispvs = NULL;
4766 lighttrispvs = NULL;
4768 // check if light is illuminating any visible leafs
4771 for (i = 0; i < numleafs; i++)
4772 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4778 // make a list of lit entities and shadow casting entities
4779 numlightentities = 0;
4780 numlightentities_noselfshadow = 0;
4781 numshadowentities = 0;
4782 numshadowentities_noselfshadow = 0;
4784 // add dynamic entities that are lit by the light
4785 for (i = 0; i < r_refdef.scene.numentities; i++)
4788 entity_render_t *ent = r_refdef.scene.entities[i];
4790 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4792 // skip the object entirely if it is not within the valid
4793 // shadow-casting region (which includes the lit region)
4794 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
4796 if (!(model = ent->model))
4798 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4800 // this entity wants to receive light, is visible, and is
4801 // inside the light box
4802 // TODO: check if the surfaces in the model can receive light
4803 // so now check if it's in a leaf seen by the light
4804 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))
4806 if (ent->flags & RENDER_NOSELFSHADOW)
4807 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
4809 lightentities[numlightentities++] = ent;
4810 // since it is lit, it probably also casts a shadow...
4811 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4812 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4813 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4815 // note: exterior models without the RENDER_NOSELFSHADOW
4816 // flag still create a RENDER_NOSELFSHADOW shadow but
4817 // are lit normally, this means that they are
4818 // self-shadowing but do not shadow other
4819 // RENDER_NOSELFSHADOW entities such as the gun
4820 // (very weird, but keeps the player shadow off the gun)
4821 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4822 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4824 shadowentities[numshadowentities++] = ent;
4827 else if (ent->flags & RENDER_SHADOW)
4829 // this entity is not receiving light, but may still need to
4831 // TODO: check if the surfaces in the model can cast shadow
4832 // now check if it is in a leaf seen by the light
4833 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))
4835 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4836 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4837 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4839 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4840 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4842 shadowentities[numshadowentities++] = ent;
4847 // return if there's nothing at all to light
4848 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4851 // count this light in the r_speeds
4852 r_refdef.stats[r_stat_lights]++;
4854 // flag it as worth drawing later
4855 rtlight->draw = true;
4857 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
4858 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4860 numshadowentities = numshadowentities_noselfshadow = 0;
4861 rtlight->castshadows = castshadows;
4863 // cache all the animated entities that cast a shadow but are not visible
4864 for (i = 0; i < numshadowentities; i++)
4865 R_AnimCache_GetEntity(shadowentities[i], false, false);
4866 for (i = 0; i < numshadowentities_noselfshadow; i++)
4867 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4869 // 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)
4870 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
4872 for (i = 0; i < numshadowentities_noselfshadow; i++)
4873 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
4874 numshadowentities_noselfshadow = 0;
4877 // we can convert noselfshadow to regular if there are no casters of that type
4878 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
4880 for (i = 0; i < numlightentities_noselfshadow; i++)
4881 lightentities[numlightentities++] = lightentities_noselfshadow[i];
4882 numlightentities_noselfshadow = 0;
4885 // allocate some temporary memory for rendering this light later in the frame
4886 // reusable buffers need to be copied, static data can be used as-is
4887 rtlight->cached_numlightentities = numlightentities;
4888 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
4889 rtlight->cached_numshadowentities = numshadowentities;
4890 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4891 rtlight->cached_numsurfaces = numsurfaces;
4892 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4893 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4894 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4895 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4896 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4898 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4899 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4900 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4901 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4902 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4906 // compiled light data
4907 rtlight->cached_shadowtrispvs = shadowtrispvs;
4908 rtlight->cached_lighttrispvs = lighttrispvs;
4909 rtlight->cached_surfacelist = surfacelist;
4912 if (R_Shadow_ShadowMappingEnabled())
4914 // figure out the shadowmapping parameters for this light
4915 vec3_t nearestpoint;
4918 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4919 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4920 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4921 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4922 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
4923 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4924 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4925 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4926 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
4930 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
4934 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4935 int numlightentities;
4936 int numlightentities_noselfshadow;
4937 int numshadowentities;
4938 int numshadowentities_noselfshadow;
4939 entity_render_t **lightentities;
4940 entity_render_t **lightentities_noselfshadow;
4941 entity_render_t **shadowentities;
4942 entity_render_t **shadowentities_noselfshadow;
4944 static unsigned char entitysides[MAX_EDICTS];
4945 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4951 matrix4x4_t radiustolight;
4953 // check if we cached this light this frame (meaning it is worth drawing)
4954 if (!rtlight->draw || !rtlight->castshadows)
4957 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
4958 if (rtlight->shadowmapatlassidesize == 0)
4960 rtlight->castshadows = false;
4964 // set up a scissor rectangle for this light
4965 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4968 // don't let sound skip if going slow
4969 if (r_refdef.scene.extraupdate)
4972 numlightentities = rtlight->cached_numlightentities;
4973 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4974 numshadowentities = rtlight->cached_numshadowentities;
4975 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4976 numsurfaces = rtlight->cached_numsurfaces;
4977 lightentities = rtlight->cached_lightentities;
4978 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4979 shadowentities = rtlight->cached_shadowentities;
4980 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4981 shadowtrispvs = rtlight->cached_shadowtrispvs;
4982 lighttrispvs = rtlight->cached_lighttrispvs;
4983 surfacelist = rtlight->cached_surfacelist;
4985 // make this the active rtlight for rendering purposes
4986 R_Shadow_RenderMode_ActiveLight(rtlight);
4988 radiustolight = rtlight->matrix_worldtolight;
4989 Matrix4x4_Abs(&radiustolight);
4991 size = rtlight->shadowmapatlassidesize;
4992 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4994 surfacesides = NULL;
4999 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
5001 castermask = rtlight->static_shadowmap_casters;
5002 receivermask = rtlight->static_shadowmap_receivers;
5006 surfacesides = r_shadow_buffer_surfacesides;
5007 for (i = 0; i < numsurfaces; i++)
5009 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
5010 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
5011 castermask |= surfacesides[i];
5012 receivermask |= surfacesides[i];
5017 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
5018 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
5019 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
5020 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
5022 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
5026 for (i = 0; i < numshadowentities; i++)
5027 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
5028 for (i = 0; i < numshadowentities_noselfshadow; i++)
5029 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
5032 // there is no need to render shadows for sides that have no receivers...
5033 castermask &= receivermask;
5035 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
5037 // render shadow casters into shadowmaps for this light
5038 for (side = 0; side < 6; side++)
5040 int bit = 1 << side;
5041 if (castermask & bit)
5043 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
5045 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
5046 for (i = 0; i < numshadowentities; i++)
5047 if (entitysides[i] & bit)
5048 R_Shadow_DrawEntityShadow(shadowentities[i]);
5049 for (i = 0; i < numshadowentities_noselfshadow; i++)
5050 if (entitysides_noselfshadow[i] & bit)
5051 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5054 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
5055 if (numshadowentities_noselfshadow)
5057 for (side = 0; side < 6; side++)
5059 int bit = 1 << side;
5060 if (castermask & bit)
5062 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
5064 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
5065 for (i = 0; i < numshadowentities; i++)
5066 if (entitysides[i] & bit)
5067 R_Shadow_DrawEntityShadow(shadowentities[i]);
5073 static void R_Shadow_DrawLight(rtlight_t *rtlight)
5077 unsigned char *shadowtrispvs, *lighttrispvs;
5078 int numlightentities;
5079 int numlightentities_noselfshadow;
5080 int numshadowentities;
5081 int numshadowentities_noselfshadow;
5082 entity_render_t **lightentities;
5083 entity_render_t **lightentities_noselfshadow;
5084 entity_render_t **shadowentities;
5085 entity_render_t **shadowentities_noselfshadow;
5087 qboolean castshadows;
5089 // check if we cached this light this frame (meaning it is worth drawing)
5093 // set up a scissor rectangle for this light
5094 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
5097 // don't let sound skip if going slow
5098 if (r_refdef.scene.extraupdate)
5101 numlightentities = rtlight->cached_numlightentities;
5102 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
5103 numshadowentities = rtlight->cached_numshadowentities;
5104 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
5105 numsurfaces = rtlight->cached_numsurfaces;
5106 lightentities = rtlight->cached_lightentities;
5107 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
5108 shadowentities = rtlight->cached_shadowentities;
5109 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
5110 shadowtrispvs = rtlight->cached_shadowtrispvs;
5111 lighttrispvs = rtlight->cached_lighttrispvs;
5112 surfacelist = rtlight->cached_surfacelist;
5113 castshadows = rtlight->castshadows;
5115 // make this the active rtlight for rendering purposes
5116 R_Shadow_RenderMode_ActiveLight(rtlight);
5118 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
5120 // optionally draw visible shape of the shadow volumes
5121 // for performance analysis by level designers
5122 R_Shadow_RenderMode_VisibleShadowVolumes();
5124 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
5125 for (i = 0;i < numshadowentities;i++)
5126 R_Shadow_DrawEntityShadow(shadowentities[i]);
5127 for (i = 0;i < numshadowentities_noselfshadow;i++)
5128 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5129 R_Shadow_RenderMode_VisibleLighting(false, false);
5132 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
5134 // optionally draw the illuminated areas
5135 // for performance analysis by level designers
5136 R_Shadow_RenderMode_VisibleLighting(false, false);
5138 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5139 for (i = 0;i < numlightentities;i++)
5140 R_Shadow_DrawEntityLight(lightentities[i]);
5141 for (i = 0;i < numlightentities_noselfshadow;i++)
5142 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5145 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
5149 float shadowmapoffsetnoselfshadow = 0;
5150 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
5151 Matrix4x4_Abs(&radiustolight);
5153 size = rtlight->shadowmapatlassidesize;
5154 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
5156 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
5158 if (rtlight->cached_numshadowentities_noselfshadow)
5159 shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
5161 // render lighting using the depth texture as shadowmap
5162 // draw lighting in the unmasked areas
5163 if (numsurfaces + numlightentities)
5165 R_Shadow_RenderMode_Lighting(false, false, true, false);
5166 // draw lighting in the unmasked areas
5168 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5169 for (i = 0; i < numlightentities; i++)
5170 R_Shadow_DrawEntityLight(lightentities[i]);
5172 // offset to the noselfshadow part of the atlas and draw those too
5173 if (numlightentities_noselfshadow)
5175 R_Shadow_RenderMode_Lighting(false, false, true, true);
5176 for (i = 0; i < numlightentities_noselfshadow; i++)
5177 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5180 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5181 if (r_shadow_usingdeferredprepass)
5182 R_Shadow_RenderMode_DrawDeferredLight(true);
5184 else if (castshadows && vid.stencil)
5186 // draw stencil shadow volumes to mask off pixels that are in shadow
5187 // so that they won't receive lighting
5188 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
5189 R_Shadow_ClearStencil();
5192 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
5193 for (i = 0;i < numshadowentities;i++)
5194 R_Shadow_DrawEntityShadow(shadowentities[i]);
5196 // draw lighting in the unmasked areas
5197 R_Shadow_RenderMode_Lighting(true, false, false, false);
5198 for (i = 0;i < numlightentities_noselfshadow;i++)
5199 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5201 for (i = 0;i < numshadowentities_noselfshadow;i++)
5202 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5204 // draw lighting in the unmasked areas
5205 R_Shadow_RenderMode_Lighting(true, false, false, false);
5207 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5208 for (i = 0;i < numlightentities;i++)
5209 R_Shadow_DrawEntityLight(lightentities[i]);
5211 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5212 if (r_shadow_usingdeferredprepass)
5213 R_Shadow_RenderMode_DrawDeferredLight(false);
5217 // draw lighting in the unmasked areas
5218 R_Shadow_RenderMode_Lighting(false, false, false, false);
5220 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5221 for (i = 0;i < numlightentities;i++)
5222 R_Shadow_DrawEntityLight(lightentities[i]);
5223 for (i = 0;i < numlightentities_noselfshadow;i++)
5224 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5226 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5227 if (r_shadow_usingdeferredprepass)
5228 R_Shadow_RenderMode_DrawDeferredLight(false);
5232 static void R_Shadow_FreeDeferred(void)
5234 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
5235 r_shadow_prepassgeometryfbo = 0;
5237 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
5238 r_shadow_prepasslightingdiffusespecularfbo = 0;
5240 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
5241 r_shadow_prepasslightingdiffusefbo = 0;
5243 if (r_shadow_prepassgeometrydepthbuffer)
5244 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
5245 r_shadow_prepassgeometrydepthbuffer = NULL;
5247 if (r_shadow_prepassgeometrynormalmaptexture)
5248 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
5249 r_shadow_prepassgeometrynormalmaptexture = NULL;
5251 if (r_shadow_prepasslightingdiffusetexture)
5252 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
5253 r_shadow_prepasslightingdiffusetexture = NULL;
5255 if (r_shadow_prepasslightingspeculartexture)
5256 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
5257 r_shadow_prepasslightingspeculartexture = NULL;
5260 void R_Shadow_DrawPrepass(void)
5264 entity_render_t *ent;
5265 float clearcolor[4];
5267 R_Mesh_ResetTextureState();
5269 GL_ColorMask(1,1,1,1);
5270 GL_BlendFunc(GL_ONE, GL_ZERO);
5273 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5274 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
5275 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
5276 if (r_timereport_active)
5277 R_TimeReport("prepasscleargeom");
5279 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
5280 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
5281 if (r_timereport_active)
5282 R_TimeReport("prepassworld");
5284 for (i = 0;i < r_refdef.scene.numentities;i++)
5286 if (!r_refdef.viewcache.entityvisible[i])
5288 ent = r_refdef.scene.entities[i];
5289 if (ent->model && ent->model->DrawPrepass != NULL)
5290 ent->model->DrawPrepass(ent);
5293 if (r_timereport_active)
5294 R_TimeReport("prepassmodels");
5296 GL_DepthMask(false);
5297 GL_ColorMask(1,1,1,1);
5300 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5301 Vector4Set(clearcolor, 0, 0, 0, 0);
5302 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
5303 if (r_timereport_active)
5304 R_TimeReport("prepassclearlit");
5306 R_Shadow_RenderMode_Begin();
5308 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5309 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5311 R_Shadow_RenderMode_End();
5313 if (r_timereport_active)
5314 R_TimeReport("prepasslights");
5317 #define MAX_SCENELIGHTS 65536
5318 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
5320 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
5322 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
5324 r_shadow_scenemaxlights *= 2;
5325 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
5326 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
5328 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
5332 void R_Shadow_DrawLightSprites(void);
5333 void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
5342 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
5343 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
5344 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
5346 if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
5347 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
5348 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
5349 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
5350 r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) ||
5351 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
5352 r_shadow_shadowmapborder != shadowmapborder ||
5353 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
5354 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
5355 R_Shadow_FreeShadowMaps();
5357 r_shadow_fb_fbo = fbo;
5358 r_shadow_fb_depthtexture = depthtexture;
5359 r_shadow_fb_colortexture = colortexture;
5361 r_shadow_usingshadowmaportho = false;
5363 switch (vid.renderpath)
5365 case RENDERPATH_GL20:
5366 case RENDERPATH_D3D9:
5367 case RENDERPATH_D3D10:
5368 case RENDERPATH_D3D11:
5369 case RENDERPATH_SOFT:
5371 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
5373 r_shadow_usingdeferredprepass = false;
5374 if (r_shadow_prepass_width)
5375 R_Shadow_FreeDeferred();
5376 r_shadow_prepass_width = r_shadow_prepass_height = 0;
5380 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
5382 R_Shadow_FreeDeferred();
5384 r_shadow_usingdeferredprepass = true;
5385 r_shadow_prepass_width = vid.width;
5386 r_shadow_prepass_height = vid.height;
5387 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
5388 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);
5389 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);
5390 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);
5392 // set up the geometry pass fbo (depth + normalmap)
5393 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5394 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5395 // render depth into a renderbuffer and other important properties into the normalmap texture
5397 // set up the lighting pass fbo (diffuse + specular)
5398 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5399 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5400 // render diffuse into one texture and specular into another,
5401 // with depth and normalmap bound as textures,
5402 // with depth bound as attachment as well
5404 // set up the lighting pass fbo (diffuse)
5405 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5406 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5407 // render diffuse into one texture,
5408 // with depth and normalmap bound as textures,
5409 // with depth bound as attachment as well
5413 case RENDERPATH_GL11:
5414 case RENDERPATH_GL13:
5415 case RENDERPATH_GLES1:
5416 case RENDERPATH_GLES2:
5417 r_shadow_usingdeferredprepass = false;
5421 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);
5423 r_shadow_scenenumlights = 0;
5424 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5425 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5426 for (lightindex = 0; lightindex < range; lightindex++)
5428 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5429 if (light && (light->flags & flag))
5431 R_Shadow_PrepareLight(&light->rtlight);
5432 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5435 if (r_refdef.scene.rtdlight)
5437 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5439 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
5440 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
5443 else if (gl_flashblend.integer)
5445 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5447 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
5448 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
5449 VectorScale(rtlight->color, f, rtlight->currentcolor);
5453 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
5454 if (r_shadow_debuglight.integer >= 0)
5456 r_shadow_scenenumlights = 0;
5457 lightindex = r_shadow_debuglight.integer;
5458 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5461 R_Shadow_PrepareLight(&light->rtlight);
5462 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5466 // if we're doing shadowmaps we need to prepare the atlas layout now
5467 if (R_Shadow_ShadowMappingEnabled())
5471 // allocate shadowmaps in the atlas now
5472 // 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...
5473 for (lod = 0; lod < 16; lod++)
5475 int packing_success = 0;
5476 int packing_failure = 0;
5477 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
5478 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
5479 if (r_shadow_shadowmapatlas_modelshadows_size)
5480 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);
5481 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5483 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
5484 int size = rtlight->shadowmapsidesize >> lod;
5486 if (!rtlight->castshadows)
5488 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
5491 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
5492 if (rtlight->cached_numshadowentities_noselfshadow)
5494 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
5496 rtlight->shadowmapatlassidesize = size;
5501 // note down that we failed to pack this one, it will have to disable shadows
5502 rtlight->shadowmapatlassidesize = 0;
5506 // generally everything fits and we stop here on the first iteration
5507 if (packing_failure == 0)
5512 if (r_editlights.integer)
5513 R_Shadow_DrawLightSprites();
5516 void R_Shadow_DrawShadowMaps(void)
5518 R_Shadow_RenderMode_Begin();
5519 R_Shadow_RenderMode_ActiveLight(NULL);
5521 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
5522 R_Shadow_ClearShadowMapTexture();
5524 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
5525 if (r_shadow_shadowmapatlas_modelshadows_size)
5527 R_Shadow_DrawModelShadowMaps();
5528 // don't let sound skip if going slow
5529 if (r_refdef.scene.extraupdate)
5533 if (R_Shadow_ShadowMappingEnabled())
5536 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5537 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
5540 R_Shadow_RenderMode_End();
5543 void R_Shadow_DrawLights(void)
5547 R_Shadow_RenderMode_Begin();
5549 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5550 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5552 R_Shadow_RenderMode_End();
5555 #define MAX_MODELSHADOWS 1024
5556 static int r_shadow_nummodelshadows;
5557 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
5559 void R_Shadow_PrepareModelShadows(void)
5562 float scale, size, radius, dot1, dot2;
5563 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5564 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
5565 entity_render_t *ent;
5567 r_shadow_nummodelshadows = 0;
5568 r_shadow_shadowmapatlas_modelshadows_size = 0;
5570 if (!r_refdef.scene.numentities || r_refdef.scene.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
5573 switch (r_shadow_shadowmode)
5575 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
5576 if (r_shadows.integer >= 2)
5579 case R_SHADOW_SHADOWMODE_STENCIL:
5582 for (i = 0; i < r_refdef.scene.numentities; i++)
5584 ent = r_refdef.scene.entities[i];
5585 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5587 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5589 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5590 R_AnimCache_GetEntity(ent, false, false);
5598 size = r_shadow_shadowmaptexturesize / 4;
5599 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
5600 radius = 0.5f * size / scale;
5602 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5603 VectorCopy(prvmshadowdir, shadowdir);
5604 VectorNormalize(shadowdir);
5605 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5606 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5607 if (fabs(dot1) <= fabs(dot2))
5608 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5610 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5611 VectorNormalize(shadowforward);
5612 CrossProduct(shadowdir, shadowforward, shadowright);
5613 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5614 VectorCopy(prvmshadowfocus, shadowfocus);
5615 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5616 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5617 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5618 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5619 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5621 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5623 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5624 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5625 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5626 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5627 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5628 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5630 for (i = 0; i < r_refdef.scene.numentities; i++)
5632 ent = r_refdef.scene.entities[i];
5633 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
5635 // cast shadows from anything of the map (submodels are optional)
5636 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5638 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5640 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5641 R_AnimCache_GetEntity(ent, false, false);
5645 if (r_shadow_nummodelshadows)
5647 r_shadow_shadowmapatlas_modelshadows_x = 0;
5648 r_shadow_shadowmapatlas_modelshadows_y = 0;
5649 r_shadow_shadowmapatlas_modelshadows_size = size;
5653 static void R_Shadow_DrawModelShadowMaps(void)
5656 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
5657 entity_render_t *ent;
5658 vec3_t relativelightorigin;
5659 vec3_t relativelightdirection, relativeforward, relativeright;
5660 vec3_t relativeshadowmins, relativeshadowmaxs;
5661 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
5662 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5664 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
5665 r_viewport_t viewport;
5667 size = r_shadow_shadowmapatlas_modelshadows_size;
5668 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
5669 radius = 0.5f / scale;
5670 nearclip = -r_shadows_throwdistance.value;
5671 farclip = r_shadows_throwdistance.value;
5672 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);
5674 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
5675 r_shadow_modelshadowmap_parameters[0] = size;
5676 r_shadow_modelshadowmap_parameters[1] = size;
5677 r_shadow_modelshadowmap_parameters[2] = 1.0;
5678 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
5679 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
5680 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
5681 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
5682 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
5683 r_shadow_usingshadowmaportho = true;
5685 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5686 VectorCopy(prvmshadowdir, shadowdir);
5687 VectorNormalize(shadowdir);
5688 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5689 VectorCopy(prvmshadowfocus, shadowfocus);
5690 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5691 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5692 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5693 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5694 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5695 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5696 if (fabs(dot1) <= fabs(dot2))
5697 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5699 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5700 VectorNormalize(shadowforward);
5701 VectorM(scale, shadowforward, &m[0]);
5702 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5704 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
5705 CrossProduct(shadowdir, shadowforward, shadowright);
5706 VectorM(scale, shadowright, &m[4]);
5707 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
5708 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
5709 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
5710 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
5711 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
5712 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);
5713 R_SetViewport(&viewport);
5715 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5717 // render into a slightly restricted region so that the borders of the
5718 // shadowmap area fade away, rather than streaking across everything
5719 // outside the usable area
5720 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
5722 for (i = 0;i < r_shadow_nummodelshadows;i++)
5724 ent = r_shadow_modelshadows[i];
5725 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5726 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
5727 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5728 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
5729 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
5730 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5731 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5732 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5733 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5734 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5735 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5736 RSurf_ActiveModelEntity(ent, false, false, false);
5737 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
5738 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5744 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
5746 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
5748 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
5749 Cvar_SetValueQuick(&r_test, 0);
5754 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
5755 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
5756 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
5757 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
5758 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
5759 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
5761 switch (vid.renderpath)
5763 case RENDERPATH_GL11:
5764 case RENDERPATH_GL13:
5765 case RENDERPATH_GL20:
5766 case RENDERPATH_SOFT:
5767 case RENDERPATH_GLES1:
5768 case RENDERPATH_GLES2:
5770 case RENDERPATH_D3D9:
5771 case RENDERPATH_D3D10:
5772 case RENDERPATH_D3D11:
5773 #ifdef MATRIX4x4_OPENGLORIENTATION
5774 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5775 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
5776 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
5777 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
5779 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5780 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
5781 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
5782 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
5788 void R_Shadow_DrawModelShadows(void)
5791 float relativethrowdistance;
5792 entity_render_t *ent;
5793 vec3_t relativelightorigin;
5794 vec3_t relativelightdirection;
5795 vec3_t relativeshadowmins, relativeshadowmaxs;
5796 vec3_t tmp, shadowdir;
5797 prvm_vec3_t prvmshadowdir;
5799 if (!r_shadow_nummodelshadows || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
5802 R_ResetViewRendering3D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5803 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
5804 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5805 R_Shadow_RenderMode_Begin();
5806 R_Shadow_RenderMode_ActiveLight(NULL);
5807 r_shadow_lightscissor[0] = r_refdef.view.x;
5808 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
5809 r_shadow_lightscissor[2] = r_refdef.view.width;
5810 r_shadow_lightscissor[3] = r_refdef.view.height;
5811 R_Shadow_RenderMode_StencilShadowVolumes(false);
5814 if (r_shadows.integer == 2)
5816 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5817 VectorCopy(prvmshadowdir, shadowdir);
5818 VectorNormalize(shadowdir);
5821 R_Shadow_ClearStencil();
5823 for (i = 0;i < r_shadow_nummodelshadows;i++)
5825 ent = r_shadow_modelshadows[i];
5827 // cast shadows from anything of the map (submodels are optional)
5828 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5829 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
5830 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
5831 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
5832 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5835 VectorNegate(ent->render_modellight_lightdir, tmp);
5836 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
5839 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
5840 RSurf_ActiveModelEntity(ent, false, false, false);
5841 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
5842 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5845 // not really the right mode, but this will disable any silly stencil features
5846 R_Shadow_RenderMode_End();
5848 // set up ortho view for rendering this pass
5849 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5850 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5851 //GL_ScissorTest(true);
5852 //R_EntityMatrix(&identitymatrix);
5853 //R_Mesh_ResetTextureState();
5854 R_ResetViewRendering2D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5856 // set up a darkening blend on shadowed areas
5857 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5858 //GL_DepthRange(0, 1);
5859 //GL_DepthTest(false);
5860 //GL_DepthMask(false);
5861 //GL_PolygonOffset(0, 0);CHECKGLERROR
5862 GL_Color(0, 0, 0, r_shadows_darken.value);
5863 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5864 //GL_DepthFunc(GL_ALWAYS);
5865 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5867 // apply the blend to the shadowed areas
5868 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5869 R_SetupShader_Generic_NoTexture(false, true);
5870 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5872 // restore the viewport
5873 R_SetViewport(&r_refdef.view.viewport);
5875 // restore other state to normal
5876 //R_Shadow_RenderMode_End();
5879 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5882 vec3_t centerorigin;
5883 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5886 // if it's too close, skip it
5887 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5889 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5892 if (usequery && r_numqueries + 2 <= r_maxqueries)
5894 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5895 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5896 // 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
5897 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5899 switch(vid.renderpath)
5901 case RENDERPATH_GL11:
5902 case RENDERPATH_GL13:
5903 case RENDERPATH_GL20:
5904 case RENDERPATH_GLES1:
5905 case RENDERPATH_GLES2:
5906 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5908 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5909 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5910 GL_DepthFunc(GL_ALWAYS);
5911 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5912 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5913 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5914 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5915 GL_DepthFunc(GL_LEQUAL);
5916 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5917 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5918 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5919 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5920 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5924 case RENDERPATH_D3D9:
5925 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5927 case RENDERPATH_D3D10:
5928 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5930 case RENDERPATH_D3D11:
5931 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5933 case RENDERPATH_SOFT:
5934 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5938 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5941 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5943 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5946 unsigned int occlude = 0;
5947 GLint allpixels = 0, visiblepixels = 0;
5949 // now we have to check the query result
5950 if (rtlight->corona_queryindex_visiblepixels)
5952 switch(vid.renderpath)
5954 case RENDERPATH_GL20:
5955 case RENDERPATH_GLES1:
5956 case RENDERPATH_GLES2:
5957 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5958 // See if we can use the GPU-side method to prevent implicit sync
5959 if (vid.support.arb_query_buffer_object) {
5960 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
5961 if (!r_shadow_occlusion_buf) {
5962 qglGenBuffersARB(1, &r_shadow_occlusion_buf);
5963 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5964 qglBufferDataARB(GL_QUERY_BUFFER_ARB, 8, NULL, GL_DYNAMIC_COPY);
5966 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5968 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(0));
5969 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4));
5970 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
5971 occlude = MATERIALFLAG_OCCLUDE;
5972 cscale *= rtlight->corona_visibility;
5980 case RENDERPATH_GL11:
5981 case RENDERPATH_GL13:
5982 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5984 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5985 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5986 if (visiblepixels < 1 || allpixels < 1)
5988 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5989 cscale *= rtlight->corona_visibility;
5995 case RENDERPATH_D3D9:
5996 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5998 case RENDERPATH_D3D10:
5999 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6001 case RENDERPATH_D3D11:
6002 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6004 case RENDERPATH_SOFT:
6005 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6013 if (CL_Cache_TraceLineSurfaces(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT).fraction < 1)
6016 VectorScale(rtlight->currentcolor, cscale, color);
6017 if (VectorLength(color) > (1.0f / 256.0f))
6020 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
6023 VectorNegate(color, color);
6024 GL_BlendEquationSubtract(true);
6026 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
6027 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);
6028 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
6030 GL_BlendEquationSubtract(false);
6034 void R_Shadow_DrawCoronas(void)
6037 qboolean usequery = false;
6042 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
6044 if (r_fb.water.renderingscene)
6046 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6047 R_EntityMatrix(&identitymatrix);
6049 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6051 // check occlusion of coronas
6052 // use GL_ARB_occlusion_query if available
6053 // otherwise use raytraces
6055 switch (vid.renderpath)
6057 case RENDERPATH_GL11:
6058 case RENDERPATH_GL13:
6059 case RENDERPATH_GL20:
6060 case RENDERPATH_GLES1:
6061 case RENDERPATH_GLES2:
6062 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
6063 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
6066 GL_ColorMask(0,0,0,0);
6067 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
6068 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
6071 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
6072 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
6074 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
6077 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6078 GL_BlendFunc(GL_ONE, GL_ZERO);
6079 GL_CullFace(GL_NONE);
6080 GL_DepthMask(false);
6081 GL_DepthRange(0, 1);
6082 GL_PolygonOffset(0, 0);
6084 R_Mesh_ResetTextureState();
6085 R_SetupShader_Generic_NoTexture(false, false);
6089 case RENDERPATH_D3D9:
6091 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6093 case RENDERPATH_D3D10:
6094 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6096 case RENDERPATH_D3D11:
6097 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6099 case RENDERPATH_SOFT:
6101 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6104 for (lightindex = 0;lightindex < range;lightindex++)
6106 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6109 rtlight = &light->rtlight;
6110 rtlight->corona_visibility = 0;
6111 rtlight->corona_queryindex_visiblepixels = 0;
6112 rtlight->corona_queryindex_allpixels = 0;
6113 if (!(rtlight->flags & flag))
6115 if (rtlight->corona <= 0)
6117 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
6119 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6121 for (i = 0;i < r_refdef.scene.numlights;i++)
6123 rtlight = r_refdef.scene.lights[i];
6124 rtlight->corona_visibility = 0;
6125 rtlight->corona_queryindex_visiblepixels = 0;
6126 rtlight->corona_queryindex_allpixels = 0;
6127 if (!(rtlight->flags & flag))
6129 if (rtlight->corona <= 0)
6131 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6134 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
6136 // now draw the coronas using the query data for intensity info
6137 for (lightindex = 0;lightindex < range;lightindex++)
6139 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6142 rtlight = &light->rtlight;
6143 if (rtlight->corona_visibility <= 0)
6145 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6147 for (i = 0;i < r_refdef.scene.numlights;i++)
6149 rtlight = r_refdef.scene.lights[i];
6150 if (rtlight->corona_visibility <= 0)
6152 if (gl_flashblend.integer)
6153 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
6155 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6161 static dlight_t *R_Shadow_NewWorldLight(void)
6163 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
6166 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)
6170 // 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
6172 // validate parameters
6176 // copy to light properties
6177 VectorCopy(origin, light->origin);
6178 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
6179 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
6180 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
6182 light->color[0] = max(color[0], 0);
6183 light->color[1] = max(color[1], 0);
6184 light->color[2] = max(color[2], 0);
6186 light->color[0] = color[0];
6187 light->color[1] = color[1];
6188 light->color[2] = color[2];
6189 light->radius = max(radius, 0);
6190 light->style = style;
6191 light->shadow = shadowenable;
6192 light->corona = corona;
6193 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
6194 light->coronasizescale = coronasizescale;
6195 light->ambientscale = ambientscale;
6196 light->diffusescale = diffusescale;
6197 light->specularscale = specularscale;
6198 light->flags = flags;
6200 // update renderable light data
6201 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
6202 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);
6205 static void R_Shadow_FreeWorldLight(dlight_t *light)
6207 if (r_shadow_selectedlight == light)
6208 r_shadow_selectedlight = NULL;
6209 R_RTLight_Uncompile(&light->rtlight);
6210 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
6213 void R_Shadow_ClearWorldLights(void)
6217 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6218 for (lightindex = 0;lightindex < range;lightindex++)
6220 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6222 R_Shadow_FreeWorldLight(light);
6224 r_shadow_selectedlight = NULL;
6227 static void R_Shadow_SelectLight(dlight_t *light)
6229 if (r_shadow_selectedlight)
6230 r_shadow_selectedlight->selected = false;
6231 r_shadow_selectedlight = light;
6232 if (r_shadow_selectedlight)
6233 r_shadow_selectedlight->selected = true;
6236 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6238 // this is never batched (there can be only one)
6240 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
6241 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6242 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6245 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6250 skinframe_t *skinframe;
6253 // this is never batched (due to the ent parameter changing every time)
6254 // so numsurfaces == 1 and surfacelist[0] == lightnumber
6255 const dlight_t *light = (dlight_t *)ent;
6258 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
6261 VectorScale(light->color, intensity, spritecolor);
6262 if (VectorLength(spritecolor) < 0.1732f)
6263 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
6264 if (VectorLength(spritecolor) > 1.0f)
6265 VectorNormalize(spritecolor);
6267 // draw light sprite
6268 if (light->cubemapname[0] && !light->shadow)
6269 skinframe = r_editlights_sprcubemapnoshadowlight;
6270 else if (light->cubemapname[0])
6271 skinframe = r_editlights_sprcubemaplight;
6272 else if (!light->shadow)
6273 skinframe = r_editlights_sprnoshadowlight;
6275 skinframe = r_editlights_sprlight;
6277 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);
6278 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6280 // draw selection sprite if light is selected
6281 if (light->selected)
6283 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6284 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6285 // VorteX todo: add normalmode/realtime mode light overlay sprites?
6289 void R_Shadow_DrawLightSprites(void)
6293 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6294 for (lightindex = 0;lightindex < range;lightindex++)
6296 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6298 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
6300 if (!r_editlights_lockcursor)
6301 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
6304 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
6309 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6310 if (lightindex >= range)
6312 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6315 rtlight = &light->rtlight;
6316 //if (!(rtlight->flags & flag))
6318 VectorCopy(rtlight->shadoworigin, origin);
6319 *radius = rtlight->radius;
6320 VectorCopy(rtlight->color, color);
6324 static void R_Shadow_SelectLightInView(void)
6326 float bestrating, rating, temp[3];
6330 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6334 if (r_editlights_lockcursor)
6336 for (lightindex = 0;lightindex < range;lightindex++)
6338 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6341 VectorSubtract(light->origin, r_refdef.view.origin, temp);
6342 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
6345 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
6346 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)
6348 bestrating = rating;
6353 R_Shadow_SelectLight(best);
6356 void R_Shadow_LoadWorldLights(void)
6358 int n, a, style, shadow, flags;
6359 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
6360 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
6361 if (cl.worldmodel == NULL)
6363 Con_Print("No map loaded.\n");
6366 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6367 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6377 for (;COM_Parse(t, true) && strcmp(
6378 if (COM_Parse(t, true))
6380 if (com_token[0] == '!')
6383 origin[0] = atof(com_token+1);
6386 origin[0] = atof(com_token);
6391 while (*s && *s != '\n' && *s != '\r')
6397 // check for modifier flags
6404 #if _MSC_VER >= 1400
6405 #define sscanf sscanf_s
6407 cubemapname[sizeof(cubemapname)-1] = 0;
6408 #if MAX_QPATH != 128
6409 #error update this code if MAX_QPATH changes
6411 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
6412 #if _MSC_VER >= 1400
6413 , sizeof(cubemapname)
6415 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
6418 flags = LIGHTFLAG_REALTIMEMODE;
6426 coronasizescale = 0.25f;
6428 VectorClear(angles);
6431 if (a < 9 || !strcmp(cubemapname, "\"\""))
6433 // remove quotes on cubemapname
6434 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
6437 namelen = strlen(cubemapname) - 2;
6438 memmove(cubemapname, cubemapname + 1, namelen);
6439 cubemapname[namelen] = '\0';
6443 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);
6446 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6454 Con_Printf("invalid rtlights file \"%s\"\n", name);
6455 Mem_Free(lightsstring);
6459 void R_Shadow_SaveWorldLights(void)
6463 size_t bufchars, bufmaxchars;
6465 char name[MAX_QPATH];
6466 char line[MAX_INPUTLINE];
6467 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
6468 // I hate lines which are 3 times my screen size :( --blub
6471 if (cl.worldmodel == NULL)
6473 Con_Print("No map loaded.\n");
6476 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6477 bufchars = bufmaxchars = 0;
6479 for (lightindex = 0;lightindex < range;lightindex++)
6481 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6484 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
6485 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);
6486 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
6487 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]);
6489 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);
6490 if (bufchars + strlen(line) > bufmaxchars)
6492 bufmaxchars = bufchars + strlen(line) + 2048;
6494 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
6498 memcpy(buf, oldbuf, bufchars);
6504 memcpy(buf + bufchars, line, strlen(line));
6505 bufchars += strlen(line);
6509 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
6514 void R_Shadow_LoadLightsFile(void)
6517 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
6518 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
6519 if (cl.worldmodel == NULL)
6521 Con_Print("No map loaded.\n");
6524 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
6525 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6533 while (*s && *s != '\n' && *s != '\r')
6539 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);
6543 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);
6546 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
6547 radius = bound(15, radius, 4096);
6548 VectorScale(color, (2.0f / (8388608.0f)), color);
6549 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6557 Con_Printf("invalid lights file \"%s\"\n", name);
6558 Mem_Free(lightsstring);
6562 // tyrlite/hmap2 light types in the delay field
6563 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
6565 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
6577 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
6578 char key[256], value[MAX_INPUTLINE];
6581 if (cl.worldmodel == NULL)
6583 Con_Print("No map loaded.\n");
6586 // try to load a .ent file first
6587 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
6588 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
6589 // and if that is not found, fall back to the bsp file entity string
6591 data = cl.worldmodel->brush.entities;
6594 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
6596 type = LIGHTTYPE_MINUSX;
6597 origin[0] = origin[1] = origin[2] = 0;
6598 originhack[0] = originhack[1] = originhack[2] = 0;
6599 angles[0] = angles[1] = angles[2] = 0;
6600 color[0] = color[1] = color[2] = 1;
6601 light[0] = light[1] = light[2] = 1;light[3] = 300;
6602 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
6612 if (!COM_ParseToken_Simple(&data, false, false, true))
6614 if (com_token[0] == '}')
6615 break; // end of entity
6616 if (com_token[0] == '_')
6617 strlcpy(key, com_token + 1, sizeof(key));
6619 strlcpy(key, com_token, sizeof(key));
6620 while (key[strlen(key)-1] == ' ') // remove trailing spaces
6621 key[strlen(key)-1] = 0;
6622 if (!COM_ParseToken_Simple(&data, false, false, true))
6624 strlcpy(value, com_token, sizeof(value));
6626 // now that we have the key pair worked out...
6627 if (!strcmp("light", key))
6629 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
6633 light[0] = vec[0] * (1.0f / 256.0f);
6634 light[1] = vec[0] * (1.0f / 256.0f);
6635 light[2] = vec[0] * (1.0f / 256.0f);
6641 light[0] = vec[0] * (1.0f / 255.0f);
6642 light[1] = vec[1] * (1.0f / 255.0f);
6643 light[2] = vec[2] * (1.0f / 255.0f);
6647 else if (!strcmp("delay", key))
6649 else if (!strcmp("origin", key))
6650 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
6651 else if (!strcmp("angle", key))
6652 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
6653 else if (!strcmp("angles", key))
6654 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
6655 else if (!strcmp("color", key))
6656 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
6657 else if (!strcmp("wait", key))
6658 fadescale = atof(value);
6659 else if (!strcmp("classname", key))
6661 if (!strncmp(value, "light", 5))
6664 if (!strcmp(value, "light_fluoro"))
6669 overridecolor[0] = 1;
6670 overridecolor[1] = 1;
6671 overridecolor[2] = 1;
6673 if (!strcmp(value, "light_fluorospark"))
6678 overridecolor[0] = 1;
6679 overridecolor[1] = 1;
6680 overridecolor[2] = 1;
6682 if (!strcmp(value, "light_globe"))
6687 overridecolor[0] = 1;
6688 overridecolor[1] = 0.8;
6689 overridecolor[2] = 0.4;
6691 if (!strcmp(value, "light_flame_large_yellow"))
6696 overridecolor[0] = 1;
6697 overridecolor[1] = 0.5;
6698 overridecolor[2] = 0.1;
6700 if (!strcmp(value, "light_flame_small_yellow"))
6705 overridecolor[0] = 1;
6706 overridecolor[1] = 0.5;
6707 overridecolor[2] = 0.1;
6709 if (!strcmp(value, "light_torch_small_white"))
6714 overridecolor[0] = 1;
6715 overridecolor[1] = 0.5;
6716 overridecolor[2] = 0.1;
6718 if (!strcmp(value, "light_torch_small_walltorch"))
6723 overridecolor[0] = 1;
6724 overridecolor[1] = 0.5;
6725 overridecolor[2] = 0.1;
6729 else if (!strcmp("style", key))
6730 style = atoi(value);
6731 else if (!strcmp("skin", key))
6732 skin = (int)atof(value);
6733 else if (!strcmp("pflags", key))
6734 pflags = (int)atof(value);
6735 //else if (!strcmp("effects", key))
6736 // effects = (int)atof(value);
6737 else if (cl.worldmodel->type == mod_brushq3)
6739 if (!strcmp("scale", key))
6740 lightscale = atof(value);
6741 if (!strcmp("fade", key))
6742 fadescale = atof(value);
6747 if (lightscale <= 0)
6751 if (color[0] == color[1] && color[0] == color[2])
6753 color[0] *= overridecolor[0];
6754 color[1] *= overridecolor[1];
6755 color[2] *= overridecolor[2];
6757 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
6758 color[0] = color[0] * light[0];
6759 color[1] = color[1] * light[1];
6760 color[2] = color[2] * light[2];
6763 case LIGHTTYPE_MINUSX:
6765 case LIGHTTYPE_RECIPX:
6767 VectorScale(color, (1.0f / 16.0f), color);
6769 case LIGHTTYPE_RECIPXX:
6771 VectorScale(color, (1.0f / 16.0f), color);
6774 case LIGHTTYPE_NONE:
6778 case LIGHTTYPE_MINUSXX:
6781 VectorAdd(origin, originhack, origin);
6783 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);
6786 Mem_Free(entfiledata);
6790 static void R_Shadow_SetCursorLocationForView(void)
6793 vec3_t dest, endpos;
6795 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
6796 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
6797 if (trace.fraction < 1)
6799 dist = trace.fraction * r_editlights_cursordistance.value;
6800 push = r_editlights_cursorpushback.value;
6804 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
6805 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
6809 VectorClear( endpos );
6811 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6812 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6813 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6816 void R_Shadow_UpdateWorldLightSelection(void)
6818 if (r_editlights.integer)
6820 R_Shadow_SetCursorLocationForView();
6821 R_Shadow_SelectLightInView();
6824 R_Shadow_SelectLight(NULL);
6827 static void R_Shadow_EditLights_Clear_f(void)
6829 R_Shadow_ClearWorldLights();
6832 void R_Shadow_EditLights_Reload_f(void)
6836 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
6837 R_Shadow_ClearWorldLights();
6838 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
6840 R_Shadow_LoadWorldLights();
6841 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6842 R_Shadow_LoadLightsFile();
6844 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
6846 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6847 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6851 static void R_Shadow_EditLights_Save_f(void)
6855 R_Shadow_SaveWorldLights();
6858 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6860 R_Shadow_ClearWorldLights();
6861 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6864 static void R_Shadow_EditLights_ImportLightsFile_f(void)
6866 R_Shadow_ClearWorldLights();
6867 R_Shadow_LoadLightsFile();
6870 static void R_Shadow_EditLights_Spawn_f(void)
6873 if (!r_editlights.integer)
6875 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6878 if (Cmd_Argc() != 1)
6880 Con_Print("r_editlights_spawn does not take parameters\n");
6883 color[0] = color[1] = color[2] = 1;
6884 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6887 static void R_Shadow_EditLights_Edit_f(void)
6889 vec3_t origin, angles, color;
6890 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6891 int style, shadows, flags, normalmode, realtimemode;
6892 char cubemapname[MAX_INPUTLINE];
6893 if (!r_editlights.integer)
6895 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6898 if (!r_shadow_selectedlight)
6900 Con_Print("No selected light.\n");
6903 VectorCopy(r_shadow_selectedlight->origin, origin);
6904 VectorCopy(r_shadow_selectedlight->angles, angles);
6905 VectorCopy(r_shadow_selectedlight->color, color);
6906 radius = r_shadow_selectedlight->radius;
6907 style = r_shadow_selectedlight->style;
6908 if (r_shadow_selectedlight->cubemapname)
6909 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6912 shadows = r_shadow_selectedlight->shadow;
6913 corona = r_shadow_selectedlight->corona;
6914 coronasizescale = r_shadow_selectedlight->coronasizescale;
6915 ambientscale = r_shadow_selectedlight->ambientscale;
6916 diffusescale = r_shadow_selectedlight->diffusescale;
6917 specularscale = r_shadow_selectedlight->specularscale;
6918 flags = r_shadow_selectedlight->flags;
6919 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6920 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6921 if (!strcmp(Cmd_Argv(1), "origin"))
6923 if (Cmd_Argc() != 5)
6925 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6928 origin[0] = atof(Cmd_Argv(2));
6929 origin[1] = atof(Cmd_Argv(3));
6930 origin[2] = atof(Cmd_Argv(4));
6932 else if (!strcmp(Cmd_Argv(1), "originscale"))
6934 if (Cmd_Argc() != 5)
6936 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6939 origin[0] *= atof(Cmd_Argv(2));
6940 origin[1] *= atof(Cmd_Argv(3));
6941 origin[2] *= atof(Cmd_Argv(4));
6943 else if (!strcmp(Cmd_Argv(1), "originx"))
6945 if (Cmd_Argc() != 3)
6947 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6950 origin[0] = atof(Cmd_Argv(2));
6952 else if (!strcmp(Cmd_Argv(1), "originy"))
6954 if (Cmd_Argc() != 3)
6956 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6959 origin[1] = atof(Cmd_Argv(2));
6961 else if (!strcmp(Cmd_Argv(1), "originz"))
6963 if (Cmd_Argc() != 3)
6965 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6968 origin[2] = atof(Cmd_Argv(2));
6970 else if (!strcmp(Cmd_Argv(1), "move"))
6972 if (Cmd_Argc() != 5)
6974 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6977 origin[0] += atof(Cmd_Argv(2));
6978 origin[1] += atof(Cmd_Argv(3));
6979 origin[2] += atof(Cmd_Argv(4));
6981 else if (!strcmp(Cmd_Argv(1), "movex"))
6983 if (Cmd_Argc() != 3)
6985 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6988 origin[0] += atof(Cmd_Argv(2));
6990 else if (!strcmp(Cmd_Argv(1), "movey"))
6992 if (Cmd_Argc() != 3)
6994 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6997 origin[1] += atof(Cmd_Argv(2));
6999 else if (!strcmp(Cmd_Argv(1), "movez"))
7001 if (Cmd_Argc() != 3)
7003 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7006 origin[2] += atof(Cmd_Argv(2));
7008 else if (!strcmp(Cmd_Argv(1), "angles"))
7010 if (Cmd_Argc() != 5)
7012 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
7015 angles[0] = atof(Cmd_Argv(2));
7016 angles[1] = atof(Cmd_Argv(3));
7017 angles[2] = atof(Cmd_Argv(4));
7019 else if (!strcmp(Cmd_Argv(1), "anglesx"))
7021 if (Cmd_Argc() != 3)
7023 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7026 angles[0] = atof(Cmd_Argv(2));
7028 else if (!strcmp(Cmd_Argv(1), "anglesy"))
7030 if (Cmd_Argc() != 3)
7032 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7035 angles[1] = atof(Cmd_Argv(2));
7037 else if (!strcmp(Cmd_Argv(1), "anglesz"))
7039 if (Cmd_Argc() != 3)
7041 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7044 angles[2] = atof(Cmd_Argv(2));
7046 else if (!strcmp(Cmd_Argv(1), "color"))
7048 if (Cmd_Argc() != 5)
7050 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
7053 color[0] = atof(Cmd_Argv(2));
7054 color[1] = atof(Cmd_Argv(3));
7055 color[2] = atof(Cmd_Argv(4));
7057 else if (!strcmp(Cmd_Argv(1), "radius"))
7059 if (Cmd_Argc() != 3)
7061 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7064 radius = atof(Cmd_Argv(2));
7066 else if (!strcmp(Cmd_Argv(1), "colorscale"))
7068 if (Cmd_Argc() == 3)
7070 double scale = atof(Cmd_Argv(2));
7077 if (Cmd_Argc() != 5)
7079 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
7082 color[0] *= atof(Cmd_Argv(2));
7083 color[1] *= atof(Cmd_Argv(3));
7084 color[2] *= atof(Cmd_Argv(4));
7087 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
7089 if (Cmd_Argc() != 3)
7091 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7094 radius *= atof(Cmd_Argv(2));
7096 else if (!strcmp(Cmd_Argv(1), "style"))
7098 if (Cmd_Argc() != 3)
7100 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7103 style = atoi(Cmd_Argv(2));
7105 else if (!strcmp(Cmd_Argv(1), "cubemap"))
7109 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7112 if (Cmd_Argc() == 3)
7113 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
7117 else if (!strcmp(Cmd_Argv(1), "shadows"))
7119 if (Cmd_Argc() != 3)
7121 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7124 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7126 else if (!strcmp(Cmd_Argv(1), "corona"))
7128 if (Cmd_Argc() != 3)
7130 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7133 corona = atof(Cmd_Argv(2));
7135 else if (!strcmp(Cmd_Argv(1), "coronasize"))
7137 if (Cmd_Argc() != 3)
7139 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7142 coronasizescale = atof(Cmd_Argv(2));
7144 else if (!strcmp(Cmd_Argv(1), "ambient"))
7146 if (Cmd_Argc() != 3)
7148 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7151 ambientscale = atof(Cmd_Argv(2));
7153 else if (!strcmp(Cmd_Argv(1), "diffuse"))
7155 if (Cmd_Argc() != 3)
7157 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7160 diffusescale = atof(Cmd_Argv(2));
7162 else if (!strcmp(Cmd_Argv(1), "specular"))
7164 if (Cmd_Argc() != 3)
7166 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7169 specularscale = atof(Cmd_Argv(2));
7171 else if (!strcmp(Cmd_Argv(1), "normalmode"))
7173 if (Cmd_Argc() != 3)
7175 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7178 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7180 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
7182 if (Cmd_Argc() != 3)
7184 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7187 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7191 Con_Print("usage: r_editlights_edit [property] [value]\n");
7192 Con_Print("Selected light's properties:\n");
7193 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7194 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7195 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7196 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
7197 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
7198 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
7199 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
7200 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
7201 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
7202 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
7203 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
7204 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
7205 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
7206 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
7209 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
7210 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
7213 static void R_Shadow_EditLights_EditAll_f(void)
7216 dlight_t *light, *oldselected;
7219 if (!r_editlights.integer)
7221 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
7225 oldselected = r_shadow_selectedlight;
7226 // EditLights doesn't seem to have a "remove" command or something so:
7227 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7228 for (lightindex = 0;lightindex < range;lightindex++)
7230 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7233 R_Shadow_SelectLight(light);
7234 R_Shadow_EditLights_Edit_f();
7236 // return to old selected (to not mess editing once selection is locked)
7237 R_Shadow_SelectLight(oldselected);
7240 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
7242 int lightnumber, lightcount;
7243 size_t lightindex, range;
7248 if (!r_editlights.integer)
7251 // update cvars so QC can query them
7252 if (r_shadow_selectedlight)
7254 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7255 Cvar_SetQuick(&r_editlights_current_origin, temp);
7256 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7257 Cvar_SetQuick(&r_editlights_current_angles, temp);
7258 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7259 Cvar_SetQuick(&r_editlights_current_color, temp);
7260 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
7261 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
7262 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
7263 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
7264 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
7265 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
7266 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
7267 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
7268 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
7269 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
7270 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
7273 // draw properties on screen
7274 if (!r_editlights_drawproperties.integer)
7276 x = vid_conwidth.value - 320;
7278 DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
7281 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7282 for (lightindex = 0;lightindex < range;lightindex++)
7284 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7287 if (light == r_shadow_selectedlight)
7288 lightnumber = (int)lightindex;
7291 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;
7292 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;
7294 if (r_shadow_selectedlight == NULL)
7296 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;
7297 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;
7298 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;
7299 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;
7300 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;
7301 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;
7302 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;
7303 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;
7304 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;
7305 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;
7306 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;
7307 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;
7308 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;
7309 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;
7310 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;
7312 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;
7313 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;
7314 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;
7315 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;
7316 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;
7317 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;
7318 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;
7319 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;
7320 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;
7321 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;
7324 static void R_Shadow_EditLights_ToggleShadow_f(void)
7326 if (!r_editlights.integer)
7328 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7331 if (!r_shadow_selectedlight)
7333 Con_Print("No selected light.\n");
7336 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);
7339 static void R_Shadow_EditLights_ToggleCorona_f(void)
7341 if (!r_editlights.integer)
7343 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7346 if (!r_shadow_selectedlight)
7348 Con_Print("No selected light.\n");
7351 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);
7354 static void R_Shadow_EditLights_Remove_f(void)
7356 if (!r_editlights.integer)
7358 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
7361 if (!r_shadow_selectedlight)
7363 Con_Print("No selected light.\n");
7366 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
7367 r_shadow_selectedlight = NULL;
7370 static void R_Shadow_EditLights_Help_f(void)
7373 "Documentation on r_editlights system:\n"
7375 "r_editlights : enable/disable editing mode\n"
7376 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
7377 "r_editlights_cursorpushback : push back cursor this far from surface\n"
7378 "r_editlights_cursorpushoff : push cursor off surface this far\n"
7379 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
7380 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
7382 "r_editlights_help : this help\n"
7383 "r_editlights_clear : remove all lights\n"
7384 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
7385 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
7386 "r_editlights_save : save to .rtlights file\n"
7387 "r_editlights_spawn : create a light with default settings\n"
7388 "r_editlights_edit command : edit selected light - more documentation below\n"
7389 "r_editlights_remove : remove selected light\n"
7390 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
7391 "r_editlights_importlightentitiesfrommap : reload light entities\n"
7392 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
7394 "origin x y z : set light location\n"
7395 "originx x: set x component of light location\n"
7396 "originy y: set y component of light location\n"
7397 "originz z: set z component of light location\n"
7398 "move x y z : adjust light location\n"
7399 "movex x: adjust x component of light location\n"
7400 "movey y: adjust y component of light location\n"
7401 "movez z: adjust z component of light location\n"
7402 "angles x y z : set light angles\n"
7403 "anglesx x: set x component of light angles\n"
7404 "anglesy y: set y component of light angles\n"
7405 "anglesz z: set z component of light angles\n"
7406 "color r g b : set color of light (can be brighter than 1 1 1)\n"
7407 "radius radius : set radius (size) of light\n"
7408 "colorscale grey : multiply color of light (1 does nothing)\n"
7409 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
7410 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
7411 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
7412 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
7413 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
7414 "cubemap basename : set filter cubemap of light\n"
7415 "shadows 1/0 : turn on/off shadows\n"
7416 "corona n : set corona intensity\n"
7417 "coronasize n : set corona size (0-1)\n"
7418 "ambient n : set ambient intensity (0-1)\n"
7419 "diffuse n : set diffuse intensity (0-1)\n"
7420 "specular n : set specular intensity (0-1)\n"
7421 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
7422 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
7423 "<nothing> : print light properties to console\n"
7427 static void R_Shadow_EditLights_CopyInfo_f(void)
7429 if (!r_editlights.integer)
7431 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
7434 if (!r_shadow_selectedlight)
7436 Con_Print("No selected light.\n");
7439 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
7440 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
7441 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
7442 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
7443 if (r_shadow_selectedlight->cubemapname)
7444 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
7446 r_shadow_bufferlight.cubemapname[0] = 0;
7447 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
7448 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
7449 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
7450 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
7451 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
7452 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
7453 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
7456 static void R_Shadow_EditLights_PasteInfo_f(void)
7458 if (!r_editlights.integer)
7460 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
7463 if (!r_shadow_selectedlight)
7465 Con_Print("No selected light.\n");
7468 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);
7471 static void R_Shadow_EditLights_Lock_f(void)
7473 if (!r_editlights.integer)
7475 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
7478 if (r_editlights_lockcursor)
7480 r_editlights_lockcursor = false;
7483 if (!r_shadow_selectedlight)
7485 Con_Print("No selected light to lock on.\n");
7488 r_editlights_lockcursor = true;
7491 static void R_Shadow_EditLights_Init(void)
7493 Cvar_RegisterVariable(&r_editlights);
7494 Cvar_RegisterVariable(&r_editlights_cursordistance);
7495 Cvar_RegisterVariable(&r_editlights_cursorpushback);
7496 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
7497 Cvar_RegisterVariable(&r_editlights_cursorgrid);
7498 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
7499 Cvar_RegisterVariable(&r_editlights_drawproperties);
7500 Cvar_RegisterVariable(&r_editlights_current_origin);
7501 Cvar_RegisterVariable(&r_editlights_current_angles);
7502 Cvar_RegisterVariable(&r_editlights_current_color);
7503 Cvar_RegisterVariable(&r_editlights_current_radius);
7504 Cvar_RegisterVariable(&r_editlights_current_corona);
7505 Cvar_RegisterVariable(&r_editlights_current_coronasize);
7506 Cvar_RegisterVariable(&r_editlights_current_style);
7507 Cvar_RegisterVariable(&r_editlights_current_shadows);
7508 Cvar_RegisterVariable(&r_editlights_current_cubemap);
7509 Cvar_RegisterVariable(&r_editlights_current_ambient);
7510 Cvar_RegisterVariable(&r_editlights_current_diffuse);
7511 Cvar_RegisterVariable(&r_editlights_current_specular);
7512 Cvar_RegisterVariable(&r_editlights_current_normalmode);
7513 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
7514 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
7515 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
7516 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)");
7517 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
7518 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
7519 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
7520 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)");
7521 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
7522 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
7523 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
7524 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
7525 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
7526 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
7527 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)");
7528 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
7534 =============================================================================
7538 =============================================================================
7541 void R_CompleteLightPoint(float *ambient, float *diffuse, float *lightdir, const vec3_t p, const int flags, float lightmapintensity, float ambientintensity)
7543 int i, numlights, flag, q;
7546 float relativepoint[3];
7551 float sa[3], sx[3], sy[3], sz[3], sd[3];
7554 // use first order spherical harmonics to combine directional lights
7555 for (q = 0; q < 3; q++)
7556 sa[q] = sx[q] = sy[q] = sz[q] = sd[q] = 0;
7558 if (flags & LP_LIGHTMAP)
7560 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7562 float tempambient[3];
7563 for (q = 0; q < 3; q++)
7564 tempambient[q] = color[q] = relativepoint[q] = 0;
7565 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
7566 // calculate a weighted average light direction as well
7567 intensity = VectorLength(color);
7568 for (q = 0; q < 3; q++)
7570 sa[q] += (0.5f * color[q] + tempambient[q]) * lightmapintensity;
7571 sx[q] += (relativepoint[0] * color[q]) * lightmapintensity;
7572 sy[q] += (relativepoint[1] * color[q]) * lightmapintensity;
7573 sz[q] += (relativepoint[2] * color[q]) * lightmapintensity;
7574 sd[q] += (intensity * relativepoint[q]) * lightmapintensity;
7579 // unlit map - fullbright but scaled by lightmapintensity
7580 for (q = 0; q < 3; q++)
7581 sa[q] += lightmapintensity;
7585 if (flags & LP_RTWORLD)
7587 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7588 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7589 for (i = 0; i < numlights; i++)
7591 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7594 light = &dlight->rtlight;
7595 if (!(light->flags & flag))
7598 lightradius2 = light->radius * light->radius;
7599 VectorSubtract(light->shadoworigin, p, relativepoint);
7600 dist2 = VectorLength2(relativepoint);
7601 if (dist2 >= lightradius2)
7603 dist = sqrt(dist2) / light->radius;
7604 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
7605 if (intensity <= 0.0f)
7607 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)
7609 for (q = 0; q < 3; q++)
7610 color[q] = light->currentcolor[q] * intensity;
7611 intensity = VectorLength(color);
7612 VectorNormalize(relativepoint);
7613 for (q = 0; q < 3; q++)
7615 sa[q] += 0.5f * color[q];
7616 sx[q] += relativepoint[0] * color[q];
7617 sy[q] += relativepoint[1] * color[q];
7618 sz[q] += relativepoint[2] * color[q];
7619 sd[q] += intensity * relativepoint[q];
7622 // FIXME: sample bouncegrid too!
7625 if (flags & LP_DYNLIGHT)
7628 for (i = 0;i < r_refdef.scene.numlights;i++)
7630 light = r_refdef.scene.lights[i];
7632 lightradius2 = light->radius * light->radius;
7633 VectorSubtract(light->shadoworigin, p, relativepoint);
7634 dist2 = VectorLength2(relativepoint);
7635 if (dist2 >= lightradius2)
7637 dist = sqrt(dist2) / light->radius;
7638 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
7639 if (intensity <= 0.0f)
7641 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)
7643 for (q = 0; q < 3; q++)
7644 color[q] = light->currentcolor[q] * intensity;
7645 intensity = VectorLength(color);
7646 VectorNormalize(relativepoint);
7647 for (q = 0; q < 3; q++)
7649 sa[q] += 0.5f * color[q];
7650 sx[q] += relativepoint[0] * color[q];
7651 sy[q] += relativepoint[1] * color[q];
7652 sz[q] += relativepoint[2] * color[q];
7653 sd[q] += intensity * relativepoint[q];
7658 // calculate the weighted-average light direction (bentnormal)
7659 for (q = 0; q < 3; q++)
7660 lightdir[q] = sd[q];
7661 VectorNormalize(lightdir);
7662 for (q = 0; q < 3; q++)
7664 // extract the diffuse color along the chosen direction and scale it
7665 diffuse[q] = (lightdir[0] * sx[q] + lightdir[1] * sy[q] + lightdir[2] * sz[q]);
7666 // subtract some of diffuse from ambient
7667 ambient[q] = sa[q] + -0.333f * diffuse[q] + ambientintensity;