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", "4", "shadowmap size bias for filtering"};
329 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
330 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
331 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
332 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
333 cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
334 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
335 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
336 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect OpenGL 2.0 render path)"};
337 cvar_t r_shadow_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 vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
3884 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3885 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, 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 vec3_t lightcolor, float ambientscale, float diffusescale)
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 *surfacecolor = rsurface.texture->dlightcolor;
3985 const float *surfacepants = rsurface.colormap_pantscolor;
3986 const float *surfaceshirt = rsurface.colormap_shirtcolor;
3987 rtexture_t *basetexture = rsurface.texture->basetexture;
3988 rtexture_t *pantstexture = rsurface.texture->pantstexture;
3989 rtexture_t *shirttexture = rsurface.texture->shirttexture;
3990 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3991 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3992 ambientscale *= 2 * r_refdef.view.colorscale;
3993 diffusescale *= 2 * r_refdef.view.colorscale;
3994 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3995 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3996 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3997 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3998 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3999 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
4000 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
4001 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
4002 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4003 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
4004 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
4005 R_Mesh_TexBind(0, basetexture);
4006 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
4007 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
4008 switch(r_shadow_rendermode)
4010 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
4011 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
4012 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
4013 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
4014 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4016 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
4017 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
4018 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
4019 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
4020 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4022 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
4023 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
4024 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
4025 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
4026 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4028 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
4033 //R_Mesh_TexBind(0, basetexture);
4034 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
4037 R_Mesh_TexBind(0, pantstexture);
4038 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
4042 R_Mesh_TexBind(0, shirttexture);
4043 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
4047 extern cvar_t gl_lightmaps;
4048 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
4050 float ambientscale, diffusescale, specularscale;
4052 float lightcolor[3];
4053 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
4054 ambientscale = rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient;
4055 diffusescale = rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient);
4056 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
4057 if (!r_shadow_usenormalmap.integer)
4059 ambientscale += 1.0f * diffusescale;
4063 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
4065 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
4068 VectorNegate(lightcolor, lightcolor);
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, lightcolor, ambientscale, diffusescale, specularscale);
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, lightcolor, ambientscale, diffusescale);
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_ActiveWorldEntity();
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_ActiveWorldEntity/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_ActiveWorldEntity();
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_ActiveWorldEntity/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_ActiveWorldEntity/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_ActiveWorldEntity();
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_ActiveWorldEntity/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_ActiveWorldEntity/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.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 = 2 * r_shadow_shadowmapmaxsize;
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_ActiveWorldEntity/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 if(ent->entitynumber != 0)
5837 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
5839 // FIXME handle this
5840 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5844 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
5845 int entnum, entnum2, recursion;
5846 entnum = entnum2 = ent->entitynumber;
5847 for(recursion = 32; recursion > 0; --recursion)
5849 entnum2 = cl.entities[entnum].state_current.tagentity;
5850 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
5855 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
5857 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
5858 // transform into modelspace of OUR entity
5859 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
5860 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
5863 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5867 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5870 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
5871 RSurf_ActiveModelEntity(ent, false, false, false);
5872 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
5873 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5876 // not really the right mode, but this will disable any silly stencil features
5877 R_Shadow_RenderMode_End();
5879 // set up ortho view for rendering this pass
5880 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5881 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5882 //GL_ScissorTest(true);
5883 //R_EntityMatrix(&identitymatrix);
5884 //R_Mesh_ResetTextureState();
5885 R_ResetViewRendering2D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5887 // set up a darkening blend on shadowed areas
5888 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5889 //GL_DepthRange(0, 1);
5890 //GL_DepthTest(false);
5891 //GL_DepthMask(false);
5892 //GL_PolygonOffset(0, 0);CHECKGLERROR
5893 GL_Color(0, 0, 0, r_shadows_darken.value);
5894 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5895 //GL_DepthFunc(GL_ALWAYS);
5896 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5898 // apply the blend to the shadowed areas
5899 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5900 R_SetupShader_Generic_NoTexture(false, true);
5901 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5903 // restore the viewport
5904 R_SetViewport(&r_refdef.view.viewport);
5906 // restore other state to normal
5907 //R_Shadow_RenderMode_End();
5910 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5913 vec3_t centerorigin;
5914 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5917 // if it's too close, skip it
5918 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5920 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5923 if (usequery && r_numqueries + 2 <= r_maxqueries)
5925 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5926 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5927 // 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
5928 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5930 switch(vid.renderpath)
5932 case RENDERPATH_GL11:
5933 case RENDERPATH_GL13:
5934 case RENDERPATH_GL20:
5935 case RENDERPATH_GLES1:
5936 case RENDERPATH_GLES2:
5937 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5939 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5940 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5941 GL_DepthFunc(GL_ALWAYS);
5942 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5943 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5944 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5945 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5946 GL_DepthFunc(GL_LEQUAL);
5947 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5948 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5949 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5950 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5951 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5955 case RENDERPATH_D3D9:
5956 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5958 case RENDERPATH_D3D10:
5959 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5961 case RENDERPATH_D3D11:
5962 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5964 case RENDERPATH_SOFT:
5965 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5969 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5972 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5974 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5977 unsigned int occlude = 0;
5978 GLint allpixels = 0, visiblepixels = 0;
5980 // now we have to check the query result
5981 if (rtlight->corona_queryindex_visiblepixels)
5983 switch(vid.renderpath)
5985 case RENDERPATH_GL20:
5986 case RENDERPATH_GLES1:
5987 case RENDERPATH_GLES2:
5988 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5989 // See if we can use the GPU-side method to prevent implicit sync
5990 if (vid.support.arb_query_buffer_object) {
5991 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
5992 if (!r_shadow_occlusion_buf) {
5993 qglGenBuffersARB(1, &r_shadow_occlusion_buf);
5994 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5995 qglBufferDataARB(GL_QUERY_BUFFER_ARB, 8, NULL, GL_DYNAMIC_COPY);
5997 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5999 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(0));
6000 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4));
6001 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
6002 occlude = MATERIALFLAG_OCCLUDE;
6003 cscale *= rtlight->corona_visibility;
6011 case RENDERPATH_GL11:
6012 case RENDERPATH_GL13:
6013 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
6015 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
6016 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
6017 if (visiblepixels < 1 || allpixels < 1)
6019 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
6020 cscale *= rtlight->corona_visibility;
6026 case RENDERPATH_D3D9:
6027 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6029 case RENDERPATH_D3D10:
6030 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6032 case RENDERPATH_D3D11:
6033 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6035 case RENDERPATH_SOFT:
6036 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6044 if (CL_Cache_TraceLineSurfaces(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT).fraction < 1)
6047 VectorScale(rtlight->currentcolor, cscale, color);
6048 if (VectorLength(color) > (1.0f / 256.0f))
6051 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
6054 VectorNegate(color, color);
6055 GL_BlendEquationSubtract(true);
6057 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
6058 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);
6059 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
6061 GL_BlendEquationSubtract(false);
6065 void R_Shadow_DrawCoronas(void)
6068 qboolean usequery = false;
6073 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
6075 if (r_fb.water.renderingscene)
6077 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6078 R_EntityMatrix(&identitymatrix);
6080 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6082 // check occlusion of coronas
6083 // use GL_ARB_occlusion_query if available
6084 // otherwise use raytraces
6086 switch (vid.renderpath)
6088 case RENDERPATH_GL11:
6089 case RENDERPATH_GL13:
6090 case RENDERPATH_GL20:
6091 case RENDERPATH_GLES1:
6092 case RENDERPATH_GLES2:
6093 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
6094 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
6097 GL_ColorMask(0,0,0,0);
6098 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
6099 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
6102 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
6103 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
6105 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
6108 RSurf_ActiveWorldEntity();
6109 GL_BlendFunc(GL_ONE, GL_ZERO);
6110 GL_CullFace(GL_NONE);
6111 GL_DepthMask(false);
6112 GL_DepthRange(0, 1);
6113 GL_PolygonOffset(0, 0);
6115 R_Mesh_ResetTextureState();
6116 R_SetupShader_Generic_NoTexture(false, false);
6120 case RENDERPATH_D3D9:
6122 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6124 case RENDERPATH_D3D10:
6125 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6127 case RENDERPATH_D3D11:
6128 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6130 case RENDERPATH_SOFT:
6132 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6135 for (lightindex = 0;lightindex < range;lightindex++)
6137 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6140 rtlight = &light->rtlight;
6141 rtlight->corona_visibility = 0;
6142 rtlight->corona_queryindex_visiblepixels = 0;
6143 rtlight->corona_queryindex_allpixels = 0;
6144 if (!(rtlight->flags & flag))
6146 if (rtlight->corona <= 0)
6148 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
6150 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6152 for (i = 0;i < r_refdef.scene.numlights;i++)
6154 rtlight = r_refdef.scene.lights[i];
6155 rtlight->corona_visibility = 0;
6156 rtlight->corona_queryindex_visiblepixels = 0;
6157 rtlight->corona_queryindex_allpixels = 0;
6158 if (!(rtlight->flags & flag))
6160 if (rtlight->corona <= 0)
6162 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6165 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
6167 // now draw the coronas using the query data for intensity info
6168 for (lightindex = 0;lightindex < range;lightindex++)
6170 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6173 rtlight = &light->rtlight;
6174 if (rtlight->corona_visibility <= 0)
6176 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6178 for (i = 0;i < r_refdef.scene.numlights;i++)
6180 rtlight = r_refdef.scene.lights[i];
6181 if (rtlight->corona_visibility <= 0)
6183 if (gl_flashblend.integer)
6184 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
6186 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6192 static dlight_t *R_Shadow_NewWorldLight(void)
6194 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
6197 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)
6201 // 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
6203 // validate parameters
6207 // copy to light properties
6208 VectorCopy(origin, light->origin);
6209 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
6210 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
6211 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
6213 light->color[0] = max(color[0], 0);
6214 light->color[1] = max(color[1], 0);
6215 light->color[2] = max(color[2], 0);
6217 light->color[0] = color[0];
6218 light->color[1] = color[1];
6219 light->color[2] = color[2];
6220 light->radius = max(radius, 0);
6221 light->style = style;
6222 light->shadow = shadowenable;
6223 light->corona = corona;
6224 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
6225 light->coronasizescale = coronasizescale;
6226 light->ambientscale = ambientscale;
6227 light->diffusescale = diffusescale;
6228 light->specularscale = specularscale;
6229 light->flags = flags;
6231 // update renderable light data
6232 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
6233 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);
6236 static void R_Shadow_FreeWorldLight(dlight_t *light)
6238 if (r_shadow_selectedlight == light)
6239 r_shadow_selectedlight = NULL;
6240 R_RTLight_Uncompile(&light->rtlight);
6241 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
6244 void R_Shadow_ClearWorldLights(void)
6248 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6249 for (lightindex = 0;lightindex < range;lightindex++)
6251 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6253 R_Shadow_FreeWorldLight(light);
6255 r_shadow_selectedlight = NULL;
6258 static void R_Shadow_SelectLight(dlight_t *light)
6260 if (r_shadow_selectedlight)
6261 r_shadow_selectedlight->selected = false;
6262 r_shadow_selectedlight = light;
6263 if (r_shadow_selectedlight)
6264 r_shadow_selectedlight->selected = true;
6267 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6269 // this is never batched (there can be only one)
6271 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
6272 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6273 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6276 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6281 skinframe_t *skinframe;
6284 // this is never batched (due to the ent parameter changing every time)
6285 // so numsurfaces == 1 and surfacelist[0] == lightnumber
6286 const dlight_t *light = (dlight_t *)ent;
6289 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
6292 VectorScale(light->color, intensity, spritecolor);
6293 if (VectorLength(spritecolor) < 0.1732f)
6294 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
6295 if (VectorLength(spritecolor) > 1.0f)
6296 VectorNormalize(spritecolor);
6298 // draw light sprite
6299 if (light->cubemapname[0] && !light->shadow)
6300 skinframe = r_editlights_sprcubemapnoshadowlight;
6301 else if (light->cubemapname[0])
6302 skinframe = r_editlights_sprcubemaplight;
6303 else if (!light->shadow)
6304 skinframe = r_editlights_sprnoshadowlight;
6306 skinframe = r_editlights_sprlight;
6308 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);
6309 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6311 // draw selection sprite if light is selected
6312 if (light->selected)
6314 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6315 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6316 // VorteX todo: add normalmode/realtime mode light overlay sprites?
6320 void R_Shadow_DrawLightSprites(void)
6324 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6325 for (lightindex = 0;lightindex < range;lightindex++)
6327 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6329 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
6331 if (!r_editlights_lockcursor)
6332 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
6335 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
6340 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6341 if (lightindex >= range)
6343 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6346 rtlight = &light->rtlight;
6347 //if (!(rtlight->flags & flag))
6349 VectorCopy(rtlight->shadoworigin, origin);
6350 *radius = rtlight->radius;
6351 VectorCopy(rtlight->color, color);
6355 static void R_Shadow_SelectLightInView(void)
6357 float bestrating, rating, temp[3];
6361 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6365 if (r_editlights_lockcursor)
6367 for (lightindex = 0;lightindex < range;lightindex++)
6369 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6372 VectorSubtract(light->origin, r_refdef.view.origin, temp);
6373 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
6376 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
6377 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)
6379 bestrating = rating;
6384 R_Shadow_SelectLight(best);
6387 void R_Shadow_LoadWorldLights(void)
6389 int n, a, style, shadow, flags;
6390 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
6391 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
6392 if (cl.worldmodel == NULL)
6394 Con_Print("No map loaded.\n");
6397 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6398 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6408 for (;COM_Parse(t, true) && strcmp(
6409 if (COM_Parse(t, true))
6411 if (com_token[0] == '!')
6414 origin[0] = atof(com_token+1);
6417 origin[0] = atof(com_token);
6422 while (*s && *s != '\n' && *s != '\r')
6428 // check for modifier flags
6435 #if _MSC_VER >= 1400
6436 #define sscanf sscanf_s
6438 cubemapname[sizeof(cubemapname)-1] = 0;
6439 #if MAX_QPATH != 128
6440 #error update this code if MAX_QPATH changes
6442 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
6443 #if _MSC_VER >= 1400
6444 , sizeof(cubemapname)
6446 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
6449 flags = LIGHTFLAG_REALTIMEMODE;
6457 coronasizescale = 0.25f;
6459 VectorClear(angles);
6462 if (a < 9 || !strcmp(cubemapname, "\"\""))
6464 // remove quotes on cubemapname
6465 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
6468 namelen = strlen(cubemapname) - 2;
6469 memmove(cubemapname, cubemapname + 1, namelen);
6470 cubemapname[namelen] = '\0';
6474 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);
6477 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6485 Con_Printf("invalid rtlights file \"%s\"\n", name);
6486 Mem_Free(lightsstring);
6490 void R_Shadow_SaveWorldLights(void)
6494 size_t bufchars, bufmaxchars;
6496 char name[MAX_QPATH];
6497 char line[MAX_INPUTLINE];
6498 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
6499 // I hate lines which are 3 times my screen size :( --blub
6502 if (cl.worldmodel == NULL)
6504 Con_Print("No map loaded.\n");
6507 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6508 bufchars = bufmaxchars = 0;
6510 for (lightindex = 0;lightindex < range;lightindex++)
6512 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6515 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
6516 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);
6517 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
6518 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]);
6520 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);
6521 if (bufchars + strlen(line) > bufmaxchars)
6523 bufmaxchars = bufchars + strlen(line) + 2048;
6525 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
6529 memcpy(buf, oldbuf, bufchars);
6535 memcpy(buf + bufchars, line, strlen(line));
6536 bufchars += strlen(line);
6540 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
6545 void R_Shadow_LoadLightsFile(void)
6548 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
6549 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
6550 if (cl.worldmodel == NULL)
6552 Con_Print("No map loaded.\n");
6555 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
6556 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6564 while (*s && *s != '\n' && *s != '\r')
6570 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);
6574 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);
6577 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
6578 radius = bound(15, radius, 4096);
6579 VectorScale(color, (2.0f / (8388608.0f)), color);
6580 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6588 Con_Printf("invalid lights file \"%s\"\n", name);
6589 Mem_Free(lightsstring);
6593 // tyrlite/hmap2 light types in the delay field
6594 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
6596 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
6608 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
6609 char key[256], value[MAX_INPUTLINE];
6612 if (cl.worldmodel == NULL)
6614 Con_Print("No map loaded.\n");
6617 // try to load a .ent file first
6618 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
6619 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
6620 // and if that is not found, fall back to the bsp file entity string
6622 data = cl.worldmodel->brush.entities;
6625 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
6627 type = LIGHTTYPE_MINUSX;
6628 origin[0] = origin[1] = origin[2] = 0;
6629 originhack[0] = originhack[1] = originhack[2] = 0;
6630 angles[0] = angles[1] = angles[2] = 0;
6631 color[0] = color[1] = color[2] = 1;
6632 light[0] = light[1] = light[2] = 1;light[3] = 300;
6633 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
6643 if (!COM_ParseToken_Simple(&data, false, false, true))
6645 if (com_token[0] == '}')
6646 break; // end of entity
6647 if (com_token[0] == '_')
6648 strlcpy(key, com_token + 1, sizeof(key));
6650 strlcpy(key, com_token, sizeof(key));
6651 while (key[strlen(key)-1] == ' ') // remove trailing spaces
6652 key[strlen(key)-1] = 0;
6653 if (!COM_ParseToken_Simple(&data, false, false, true))
6655 strlcpy(value, com_token, sizeof(value));
6657 // now that we have the key pair worked out...
6658 if (!strcmp("light", key))
6660 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
6664 light[0] = vec[0] * (1.0f / 256.0f);
6665 light[1] = vec[0] * (1.0f / 256.0f);
6666 light[2] = vec[0] * (1.0f / 256.0f);
6672 light[0] = vec[0] * (1.0f / 255.0f);
6673 light[1] = vec[1] * (1.0f / 255.0f);
6674 light[2] = vec[2] * (1.0f / 255.0f);
6678 else if (!strcmp("delay", key))
6680 else if (!strcmp("origin", key))
6681 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
6682 else if (!strcmp("angle", key))
6683 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
6684 else if (!strcmp("angles", key))
6685 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
6686 else if (!strcmp("color", key))
6687 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
6688 else if (!strcmp("wait", key))
6689 fadescale = atof(value);
6690 else if (!strcmp("classname", key))
6692 if (!strncmp(value, "light", 5))
6695 if (!strcmp(value, "light_fluoro"))
6700 overridecolor[0] = 1;
6701 overridecolor[1] = 1;
6702 overridecolor[2] = 1;
6704 if (!strcmp(value, "light_fluorospark"))
6709 overridecolor[0] = 1;
6710 overridecolor[1] = 1;
6711 overridecolor[2] = 1;
6713 if (!strcmp(value, "light_globe"))
6718 overridecolor[0] = 1;
6719 overridecolor[1] = 0.8;
6720 overridecolor[2] = 0.4;
6722 if (!strcmp(value, "light_flame_large_yellow"))
6727 overridecolor[0] = 1;
6728 overridecolor[1] = 0.5;
6729 overridecolor[2] = 0.1;
6731 if (!strcmp(value, "light_flame_small_yellow"))
6736 overridecolor[0] = 1;
6737 overridecolor[1] = 0.5;
6738 overridecolor[2] = 0.1;
6740 if (!strcmp(value, "light_torch_small_white"))
6745 overridecolor[0] = 1;
6746 overridecolor[1] = 0.5;
6747 overridecolor[2] = 0.1;
6749 if (!strcmp(value, "light_torch_small_walltorch"))
6754 overridecolor[0] = 1;
6755 overridecolor[1] = 0.5;
6756 overridecolor[2] = 0.1;
6760 else if (!strcmp("style", key))
6761 style = atoi(value);
6762 else if (!strcmp("skin", key))
6763 skin = (int)atof(value);
6764 else if (!strcmp("pflags", key))
6765 pflags = (int)atof(value);
6766 //else if (!strcmp("effects", key))
6767 // effects = (int)atof(value);
6768 else if (cl.worldmodel->type == mod_brushq3)
6770 if (!strcmp("scale", key))
6771 lightscale = atof(value);
6772 if (!strcmp("fade", key))
6773 fadescale = atof(value);
6778 if (lightscale <= 0)
6782 if (color[0] == color[1] && color[0] == color[2])
6784 color[0] *= overridecolor[0];
6785 color[1] *= overridecolor[1];
6786 color[2] *= overridecolor[2];
6788 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
6789 color[0] = color[0] * light[0];
6790 color[1] = color[1] * light[1];
6791 color[2] = color[2] * light[2];
6794 case LIGHTTYPE_MINUSX:
6796 case LIGHTTYPE_RECIPX:
6798 VectorScale(color, (1.0f / 16.0f), color);
6800 case LIGHTTYPE_RECIPXX:
6802 VectorScale(color, (1.0f / 16.0f), color);
6805 case LIGHTTYPE_NONE:
6809 case LIGHTTYPE_MINUSXX:
6812 VectorAdd(origin, originhack, origin);
6814 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);
6817 Mem_Free(entfiledata);
6821 static void R_Shadow_SetCursorLocationForView(void)
6824 vec3_t dest, endpos;
6826 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
6827 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
6828 if (trace.fraction < 1)
6830 dist = trace.fraction * r_editlights_cursordistance.value;
6831 push = r_editlights_cursorpushback.value;
6835 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
6836 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
6840 VectorClear( endpos );
6842 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6843 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6844 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6847 void R_Shadow_UpdateWorldLightSelection(void)
6849 if (r_editlights.integer)
6851 R_Shadow_SetCursorLocationForView();
6852 R_Shadow_SelectLightInView();
6855 R_Shadow_SelectLight(NULL);
6858 static void R_Shadow_EditLights_Clear_f(void)
6860 R_Shadow_ClearWorldLights();
6863 void R_Shadow_EditLights_Reload_f(void)
6867 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
6868 R_Shadow_ClearWorldLights();
6869 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
6871 R_Shadow_LoadWorldLights();
6872 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6873 R_Shadow_LoadLightsFile();
6875 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
6877 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6878 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6882 static void R_Shadow_EditLights_Save_f(void)
6886 R_Shadow_SaveWorldLights();
6889 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6891 R_Shadow_ClearWorldLights();
6892 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6895 static void R_Shadow_EditLights_ImportLightsFile_f(void)
6897 R_Shadow_ClearWorldLights();
6898 R_Shadow_LoadLightsFile();
6901 static void R_Shadow_EditLights_Spawn_f(void)
6904 if (!r_editlights.integer)
6906 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6909 if (Cmd_Argc() != 1)
6911 Con_Print("r_editlights_spawn does not take parameters\n");
6914 color[0] = color[1] = color[2] = 1;
6915 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6918 static void R_Shadow_EditLights_Edit_f(void)
6920 vec3_t origin, angles, color;
6921 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6922 int style, shadows, flags, normalmode, realtimemode;
6923 char cubemapname[MAX_INPUTLINE];
6924 if (!r_editlights.integer)
6926 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6929 if (!r_shadow_selectedlight)
6931 Con_Print("No selected light.\n");
6934 VectorCopy(r_shadow_selectedlight->origin, origin);
6935 VectorCopy(r_shadow_selectedlight->angles, angles);
6936 VectorCopy(r_shadow_selectedlight->color, color);
6937 radius = r_shadow_selectedlight->radius;
6938 style = r_shadow_selectedlight->style;
6939 if (r_shadow_selectedlight->cubemapname)
6940 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6943 shadows = r_shadow_selectedlight->shadow;
6944 corona = r_shadow_selectedlight->corona;
6945 coronasizescale = r_shadow_selectedlight->coronasizescale;
6946 ambientscale = r_shadow_selectedlight->ambientscale;
6947 diffusescale = r_shadow_selectedlight->diffusescale;
6948 specularscale = r_shadow_selectedlight->specularscale;
6949 flags = r_shadow_selectedlight->flags;
6950 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6951 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6952 if (!strcmp(Cmd_Argv(1), "origin"))
6954 if (Cmd_Argc() != 5)
6956 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6959 origin[0] = atof(Cmd_Argv(2));
6960 origin[1] = atof(Cmd_Argv(3));
6961 origin[2] = atof(Cmd_Argv(4));
6963 else if (!strcmp(Cmd_Argv(1), "originscale"))
6965 if (Cmd_Argc() != 5)
6967 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6970 origin[0] *= atof(Cmd_Argv(2));
6971 origin[1] *= atof(Cmd_Argv(3));
6972 origin[2] *= atof(Cmd_Argv(4));
6974 else if (!strcmp(Cmd_Argv(1), "originx"))
6976 if (Cmd_Argc() != 3)
6978 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6981 origin[0] = atof(Cmd_Argv(2));
6983 else if (!strcmp(Cmd_Argv(1), "originy"))
6985 if (Cmd_Argc() != 3)
6987 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6990 origin[1] = atof(Cmd_Argv(2));
6992 else if (!strcmp(Cmd_Argv(1), "originz"))
6994 if (Cmd_Argc() != 3)
6996 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6999 origin[2] = atof(Cmd_Argv(2));
7001 else if (!strcmp(Cmd_Argv(1), "move"))
7003 if (Cmd_Argc() != 5)
7005 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
7008 origin[0] += atof(Cmd_Argv(2));
7009 origin[1] += atof(Cmd_Argv(3));
7010 origin[2] += atof(Cmd_Argv(4));
7012 else if (!strcmp(Cmd_Argv(1), "movex"))
7014 if (Cmd_Argc() != 3)
7016 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7019 origin[0] += atof(Cmd_Argv(2));
7021 else if (!strcmp(Cmd_Argv(1), "movey"))
7023 if (Cmd_Argc() != 3)
7025 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7028 origin[1] += atof(Cmd_Argv(2));
7030 else if (!strcmp(Cmd_Argv(1), "movez"))
7032 if (Cmd_Argc() != 3)
7034 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7037 origin[2] += atof(Cmd_Argv(2));
7039 else if (!strcmp(Cmd_Argv(1), "angles"))
7041 if (Cmd_Argc() != 5)
7043 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
7046 angles[0] = atof(Cmd_Argv(2));
7047 angles[1] = atof(Cmd_Argv(3));
7048 angles[2] = atof(Cmd_Argv(4));
7050 else if (!strcmp(Cmd_Argv(1), "anglesx"))
7052 if (Cmd_Argc() != 3)
7054 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7057 angles[0] = atof(Cmd_Argv(2));
7059 else if (!strcmp(Cmd_Argv(1), "anglesy"))
7061 if (Cmd_Argc() != 3)
7063 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7066 angles[1] = atof(Cmd_Argv(2));
7068 else if (!strcmp(Cmd_Argv(1), "anglesz"))
7070 if (Cmd_Argc() != 3)
7072 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7075 angles[2] = atof(Cmd_Argv(2));
7077 else if (!strcmp(Cmd_Argv(1), "color"))
7079 if (Cmd_Argc() != 5)
7081 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
7084 color[0] = atof(Cmd_Argv(2));
7085 color[1] = atof(Cmd_Argv(3));
7086 color[2] = atof(Cmd_Argv(4));
7088 else if (!strcmp(Cmd_Argv(1), "radius"))
7090 if (Cmd_Argc() != 3)
7092 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7095 radius = atof(Cmd_Argv(2));
7097 else if (!strcmp(Cmd_Argv(1), "colorscale"))
7099 if (Cmd_Argc() == 3)
7101 double scale = atof(Cmd_Argv(2));
7108 if (Cmd_Argc() != 5)
7110 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
7113 color[0] *= atof(Cmd_Argv(2));
7114 color[1] *= atof(Cmd_Argv(3));
7115 color[2] *= atof(Cmd_Argv(4));
7118 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
7120 if (Cmd_Argc() != 3)
7122 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7125 radius *= atof(Cmd_Argv(2));
7127 else if (!strcmp(Cmd_Argv(1), "style"))
7129 if (Cmd_Argc() != 3)
7131 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7134 style = atoi(Cmd_Argv(2));
7136 else if (!strcmp(Cmd_Argv(1), "cubemap"))
7140 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7143 if (Cmd_Argc() == 3)
7144 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
7148 else if (!strcmp(Cmd_Argv(1), "shadows"))
7150 if (Cmd_Argc() != 3)
7152 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7155 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7157 else if (!strcmp(Cmd_Argv(1), "corona"))
7159 if (Cmd_Argc() != 3)
7161 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7164 corona = atof(Cmd_Argv(2));
7166 else if (!strcmp(Cmd_Argv(1), "coronasize"))
7168 if (Cmd_Argc() != 3)
7170 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7173 coronasizescale = atof(Cmd_Argv(2));
7175 else if (!strcmp(Cmd_Argv(1), "ambient"))
7177 if (Cmd_Argc() != 3)
7179 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7182 ambientscale = atof(Cmd_Argv(2));
7184 else if (!strcmp(Cmd_Argv(1), "diffuse"))
7186 if (Cmd_Argc() != 3)
7188 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7191 diffusescale = atof(Cmd_Argv(2));
7193 else if (!strcmp(Cmd_Argv(1), "specular"))
7195 if (Cmd_Argc() != 3)
7197 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7200 specularscale = atof(Cmd_Argv(2));
7202 else if (!strcmp(Cmd_Argv(1), "normalmode"))
7204 if (Cmd_Argc() != 3)
7206 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7209 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7211 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
7213 if (Cmd_Argc() != 3)
7215 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7218 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7222 Con_Print("usage: r_editlights_edit [property] [value]\n");
7223 Con_Print("Selected light's properties:\n");
7224 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7225 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7226 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7227 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
7228 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
7229 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
7230 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
7231 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
7232 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
7233 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
7234 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
7235 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
7236 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
7237 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
7240 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
7241 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
7244 static void R_Shadow_EditLights_EditAll_f(void)
7247 dlight_t *light, *oldselected;
7250 if (!r_editlights.integer)
7252 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
7256 oldselected = r_shadow_selectedlight;
7257 // EditLights doesn't seem to have a "remove" command or something so:
7258 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7259 for (lightindex = 0;lightindex < range;lightindex++)
7261 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7264 R_Shadow_SelectLight(light);
7265 R_Shadow_EditLights_Edit_f();
7267 // return to old selected (to not mess editing once selection is locked)
7268 R_Shadow_SelectLight(oldselected);
7271 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
7273 int lightnumber, lightcount;
7274 size_t lightindex, range;
7279 if (!r_editlights.integer)
7282 // update cvars so QC can query them
7283 if (r_shadow_selectedlight)
7285 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7286 Cvar_SetQuick(&r_editlights_current_origin, temp);
7287 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7288 Cvar_SetQuick(&r_editlights_current_angles, temp);
7289 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7290 Cvar_SetQuick(&r_editlights_current_color, temp);
7291 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
7292 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
7293 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
7294 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
7295 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
7296 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
7297 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
7298 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
7299 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
7300 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
7301 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
7304 // draw properties on screen
7305 if (!r_editlights_drawproperties.integer)
7307 x = vid_conwidth.value - 320;
7309 DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
7312 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7313 for (lightindex = 0;lightindex < range;lightindex++)
7315 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7318 if (light == r_shadow_selectedlight)
7319 lightnumber = (int)lightindex;
7322 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;
7323 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;
7325 if (r_shadow_selectedlight == NULL)
7327 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;
7328 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;
7329 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;
7330 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;
7331 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;
7332 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;
7333 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;
7334 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;
7335 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;
7336 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;
7337 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;
7338 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;
7339 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;
7340 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;
7341 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;
7343 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;
7344 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;
7345 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;
7346 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;
7347 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;
7348 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;
7349 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;
7350 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;
7351 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;
7352 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;
7355 static void R_Shadow_EditLights_ToggleShadow_f(void)
7357 if (!r_editlights.integer)
7359 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7362 if (!r_shadow_selectedlight)
7364 Con_Print("No selected light.\n");
7367 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);
7370 static void R_Shadow_EditLights_ToggleCorona_f(void)
7372 if (!r_editlights.integer)
7374 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7377 if (!r_shadow_selectedlight)
7379 Con_Print("No selected light.\n");
7382 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);
7385 static void R_Shadow_EditLights_Remove_f(void)
7387 if (!r_editlights.integer)
7389 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
7392 if (!r_shadow_selectedlight)
7394 Con_Print("No selected light.\n");
7397 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
7398 r_shadow_selectedlight = NULL;
7401 static void R_Shadow_EditLights_Help_f(void)
7404 "Documentation on r_editlights system:\n"
7406 "r_editlights : enable/disable editing mode\n"
7407 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
7408 "r_editlights_cursorpushback : push back cursor this far from surface\n"
7409 "r_editlights_cursorpushoff : push cursor off surface this far\n"
7410 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
7411 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
7413 "r_editlights_help : this help\n"
7414 "r_editlights_clear : remove all lights\n"
7415 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
7416 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
7417 "r_editlights_save : save to .rtlights file\n"
7418 "r_editlights_spawn : create a light with default settings\n"
7419 "r_editlights_edit command : edit selected light - more documentation below\n"
7420 "r_editlights_remove : remove selected light\n"
7421 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
7422 "r_editlights_importlightentitiesfrommap : reload light entities\n"
7423 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
7425 "origin x y z : set light location\n"
7426 "originx x: set x component of light location\n"
7427 "originy y: set y component of light location\n"
7428 "originz z: set z component of light location\n"
7429 "move x y z : adjust light location\n"
7430 "movex x: adjust x component of light location\n"
7431 "movey y: adjust y component of light location\n"
7432 "movez z: adjust z component of light location\n"
7433 "angles x y z : set light angles\n"
7434 "anglesx x: set x component of light angles\n"
7435 "anglesy y: set y component of light angles\n"
7436 "anglesz z: set z component of light angles\n"
7437 "color r g b : set color of light (can be brighter than 1 1 1)\n"
7438 "radius radius : set radius (size) of light\n"
7439 "colorscale grey : multiply color of light (1 does nothing)\n"
7440 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
7441 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
7442 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
7443 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
7444 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
7445 "cubemap basename : set filter cubemap of light\n"
7446 "shadows 1/0 : turn on/off shadows\n"
7447 "corona n : set corona intensity\n"
7448 "coronasize n : set corona size (0-1)\n"
7449 "ambient n : set ambient intensity (0-1)\n"
7450 "diffuse n : set diffuse intensity (0-1)\n"
7451 "specular n : set specular intensity (0-1)\n"
7452 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
7453 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
7454 "<nothing> : print light properties to console\n"
7458 static void R_Shadow_EditLights_CopyInfo_f(void)
7460 if (!r_editlights.integer)
7462 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
7465 if (!r_shadow_selectedlight)
7467 Con_Print("No selected light.\n");
7470 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
7471 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
7472 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
7473 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
7474 if (r_shadow_selectedlight->cubemapname)
7475 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
7477 r_shadow_bufferlight.cubemapname[0] = 0;
7478 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
7479 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
7480 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
7481 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
7482 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
7483 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
7484 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
7487 static void R_Shadow_EditLights_PasteInfo_f(void)
7489 if (!r_editlights.integer)
7491 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
7494 if (!r_shadow_selectedlight)
7496 Con_Print("No selected light.\n");
7499 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);
7502 static void R_Shadow_EditLights_Lock_f(void)
7504 if (!r_editlights.integer)
7506 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
7509 if (r_editlights_lockcursor)
7511 r_editlights_lockcursor = false;
7514 if (!r_shadow_selectedlight)
7516 Con_Print("No selected light to lock on.\n");
7519 r_editlights_lockcursor = true;
7522 static void R_Shadow_EditLights_Init(void)
7524 Cvar_RegisterVariable(&r_editlights);
7525 Cvar_RegisterVariable(&r_editlights_cursordistance);
7526 Cvar_RegisterVariable(&r_editlights_cursorpushback);
7527 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
7528 Cvar_RegisterVariable(&r_editlights_cursorgrid);
7529 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
7530 Cvar_RegisterVariable(&r_editlights_drawproperties);
7531 Cvar_RegisterVariable(&r_editlights_current_origin);
7532 Cvar_RegisterVariable(&r_editlights_current_angles);
7533 Cvar_RegisterVariable(&r_editlights_current_color);
7534 Cvar_RegisterVariable(&r_editlights_current_radius);
7535 Cvar_RegisterVariable(&r_editlights_current_corona);
7536 Cvar_RegisterVariable(&r_editlights_current_coronasize);
7537 Cvar_RegisterVariable(&r_editlights_current_style);
7538 Cvar_RegisterVariable(&r_editlights_current_shadows);
7539 Cvar_RegisterVariable(&r_editlights_current_cubemap);
7540 Cvar_RegisterVariable(&r_editlights_current_ambient);
7541 Cvar_RegisterVariable(&r_editlights_current_diffuse);
7542 Cvar_RegisterVariable(&r_editlights_current_specular);
7543 Cvar_RegisterVariable(&r_editlights_current_normalmode);
7544 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
7545 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
7546 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
7547 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)");
7548 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
7549 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
7550 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
7551 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)");
7552 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
7553 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
7554 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
7555 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
7556 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
7557 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
7558 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)");
7559 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
7565 =============================================================================
7569 =============================================================================
7572 void R_LightPoint(float *color, const vec3_t p, const int flags)
7574 int i, numlights, flag;
7575 float f, relativepoint[3], dist, dist2, lightradius2;
7580 if (r_fullbright.integer)
7582 VectorSet(color, 1, 1, 1);
7588 if (flags & LP_LIGHTMAP)
7590 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7592 VectorClear(diffuse);
7593 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, color, diffuse, n);
7594 VectorAdd(color, diffuse, color);
7597 VectorSet(color, 1, 1, 1);
7598 color[0] += r_refdef.scene.ambient;
7599 color[1] += r_refdef.scene.ambient;
7600 color[2] += r_refdef.scene.ambient;
7603 if (flags & LP_RTWORLD)
7605 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7606 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7607 for (i = 0; i < numlights; i++)
7609 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7612 light = &dlight->rtlight;
7613 if (!(light->flags & flag))
7616 lightradius2 = light->radius * light->radius;
7617 VectorSubtract(light->shadoworigin, p, relativepoint);
7618 dist2 = VectorLength2(relativepoint);
7619 if (dist2 >= lightradius2)
7621 dist = sqrt(dist2) / light->radius;
7622 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7625 // todo: add to both ambient and diffuse
7626 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)
7627 VectorMA(color, f, light->currentcolor, color);
7630 if (flags & LP_DYNLIGHT)
7633 for (i = 0;i < r_refdef.scene.numlights;i++)
7635 light = r_refdef.scene.lights[i];
7637 lightradius2 = light->radius * light->radius;
7638 VectorSubtract(light->shadoworigin, p, relativepoint);
7639 dist2 = VectorLength2(relativepoint);
7640 if (dist2 >= lightradius2)
7642 dist = sqrt(dist2) / light->radius;
7643 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7646 // todo: add to both ambient and diffuse
7647 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)
7648 VectorMA(color, f, light->color, color);
7653 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
7655 int i, numlights, flag;
7658 float relativepoint[3];
7667 if (r_fullbright.integer)
7669 VectorSet(ambient, 1, 1, 1);
7670 VectorClear(diffuse);
7671 VectorClear(lightdir);
7675 if (flags == LP_LIGHTMAP)
7677 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7678 VectorClear(diffuse);
7679 VectorClear(lightdir);
7680 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7681 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
7683 VectorSet(ambient, 1, 1, 1);
7687 memset(sample, 0, sizeof(sample));
7688 VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7690 if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7693 VectorClear(tempambient);
7695 VectorClear(relativepoint);
7696 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
7697 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
7698 VectorScale(color, r_refdef.lightmapintensity, color);
7699 VectorAdd(sample, tempambient, sample);
7700 VectorMA(sample , 0.5f , color, sample );
7701 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7702 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7703 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7704 // calculate a weighted average light direction as well
7705 intensity = VectorLength(color);
7706 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7709 if (flags & LP_RTWORLD)
7711 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7712 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7713 for (i = 0; i < numlights; i++)
7715 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7718 light = &dlight->rtlight;
7719 if (!(light->flags & flag))
7722 lightradius2 = light->radius * light->radius;
7723 VectorSubtract(light->shadoworigin, p, relativepoint);
7724 dist2 = VectorLength2(relativepoint);
7725 if (dist2 >= lightradius2)
7727 dist = sqrt(dist2) / light->radius;
7728 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
7729 if (intensity <= 0.0f)
7731 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)
7733 // scale down intensity to add to both ambient and diffuse
7734 //intensity *= 0.5f;
7735 VectorNormalize(relativepoint);
7736 VectorScale(light->currentcolor, intensity, color);
7737 VectorMA(sample , 0.5f , color, sample );
7738 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7739 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7740 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7741 // calculate a weighted average light direction as well
7742 intensity *= VectorLength(color);
7743 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7745 // FIXME: sample bouncegrid too!
7748 if (flags & LP_DYNLIGHT)
7751 for (i = 0;i < r_refdef.scene.numlights;i++)
7753 light = r_refdef.scene.lights[i];
7755 lightradius2 = light->radius * light->radius;
7756 VectorSubtract(light->shadoworigin, p, relativepoint);
7757 dist2 = VectorLength2(relativepoint);
7758 if (dist2 >= lightradius2)
7760 dist = sqrt(dist2) / light->radius;
7761 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
7762 if (intensity <= 0.0f)
7764 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)
7766 // scale down intensity to add to both ambient and diffuse
7767 //intensity *= 0.5f;
7768 VectorNormalize(relativepoint);
7769 VectorScale(light->currentcolor, intensity, color);
7770 VectorMA(sample , 0.5f , color, sample );
7771 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7772 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7773 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7774 // calculate a weighted average light direction as well
7775 intensity *= VectorLength(color);
7776 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7780 // calculate the direction we'll use to reduce the sample to a directional light source
7781 VectorCopy(sample + 12, dir);
7782 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
7783 VectorNormalize(dir);
7784 // extract the diffuse color along the chosen direction and scale it
7785 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
7786 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
7787 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
7788 // subtract some of diffuse from ambient
7789 VectorMA(sample, -0.333f, diffuse, ambient);
7790 // store the normalized lightdir
7791 VectorCopy(dir, lightdir);