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;
3350 float bounceminimumintensity2;
3352 //trace_t cliptrace2;
3353 //trace_t cliptrace3;
3354 unsigned int lightindex;
3356 randomseed_t randomseed;
3358 vec3_t baseshotcolor;
3364 vec_t distancetraveled;
3368 // compute a seed for the unstable random modes
3369 Math_RandomSeed_FromInts(&randomseed, 0, 0, 0, realtime * 1000.0);
3370 seed = realtime * 1000.0;
3372 r_shadow_bouncegrid_state.numsplatpaths = 0;
3374 // figure out what we want to interact with
3375 if (settings.hitmodels)
3376 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;// | SUPERCONTENTS_LIQUIDSMASK;
3378 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
3379 skipsupercontentsmask = SUPERCONTENTS_SKY; // this allows the e1m5 sky shadow to work by ignoring the sky surfaces
3380 maxbounce = settings.maxbounce;
3382 for (lightindex = 0;lightindex < range2;lightindex++)
3384 if (lightindex < range)
3386 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3389 rtlight = &light->rtlight;
3392 rtlight = r_refdef.scene.lights[lightindex - range];
3393 // note that this code used to keep track of residual photons and
3394 // distribute them evenly to achieve exactly a desired photon count,
3395 // but that caused unwanted flickering in dynamic mode
3396 shootparticles = (int)floor(rtlight->bouncegrid_photons);
3397 // skip if we won't be shooting any photons
3398 if (!shootparticles)
3400 radius = rtlight->radius * settings.lightradiusscale;
3401 //s = settings.particleintensity / shootparticles;
3402 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
3403 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
3404 if (VectorLength2(baseshotcolor) <= 0.0f)
3406 r_refdef.stats[r_stat_bouncegrid_lights]++;
3407 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
3408 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
3409 bounceminimumintensity2 = VectorLength(baseshotcolor) * settings.bounceminimumintensity2;
3411 // for seeded random we start the RNG with the position of the light
3412 if (settings.rng_seed >= 0)
3420 u.f[0] = rtlight->shadoworigin[0];
3421 u.f[1] = rtlight->shadoworigin[1];
3422 u.f[2] = rtlight->shadoworigin[2];
3424 switch (settings.rng_type)
3428 // we have to shift the seed provided by the user because the result must be odd
3429 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3] ^ (settings.rng_seed << 1));
3432 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3] ^ settings.rng_seed;
3437 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
3439 VectorCopy(baseshotcolor, shotcolor);
3440 VectorCopy(rtlight->shadoworigin, clipstart);
3441 switch (settings.rng_type)
3445 VectorLehmerRandom(&randomseed, clipend);
3446 if (settings.bounceanglediffuse)
3448 // we want random to be stable, so we still have to do all the random we would have done
3449 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3450 VectorLehmerRandom(&randomseed, bouncerandom[bouncecount]);
3454 VectorCheeseRandom(seed, clipend);
3455 if (settings.bounceanglediffuse)
3457 // we want random to be stable, so we still have to do all the random we would have done
3458 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3459 VectorCheeseRandom(seed, bouncerandom[bouncecount]);
3464 // we want a uniform distribution spherically, not merely within the sphere
3465 if (settings.normalizevectors)
3466 VectorNormalize(clipend);
3468 VectorMA(clipstart, radius, clipend, clipend);
3469 distancetraveled = 0.0f;
3470 for (bouncecount = 0;;bouncecount++)
3472 r_refdef.stats[r_stat_bouncegrid_traces]++;
3473 rtlight->bouncegrid_traces++;
3474 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
3475 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
3476 if (settings.staticmode || settings.rng_seed < 0)
3478 // static mode fires a LOT of rays but none of them are identical, so they are not cached
3479 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
3480 cliptrace = CL_TraceLine(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), NULL, hitsupercontentsmask, skipsupercontentsmask, collision_extendmovelength.value, true, false, NULL, true, true);
3484 // dynamic mode fires many rays and most will match the cache from the previous frame
3485 cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask, skipsupercontentsmask);
3487 if (bouncecount > 0 || settings.includedirectlighting)
3490 VectorCopy(cliptrace.endpos, hitpos);
3491 R_Shadow_BounceGrid_AddSplatPath(clipstart, hitpos, shotcolor, distancetraveled);
3493 distancetraveled += VectorDistance(clipstart, cliptrace.endpos);
3494 s = VectorDistance(rtlight->shadoworigin, cliptrace.endpos);
3495 if (rtlight->bouncegrid_effectiveradius < s)
3496 rtlight->bouncegrid_effectiveradius = s;
3497 if (cliptrace.fraction >= 1.0f)
3499 r_refdef.stats[r_stat_bouncegrid_hits]++;
3500 rtlight->bouncegrid_hits++;
3501 if (bouncecount >= maxbounce)
3503 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
3504 // also clamp the resulting color to never add energy, even if the user requests extreme values
3505 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
3506 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
3508 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
3509 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
3510 surfcolor[0] = min(surfcolor[0], 1.0f);
3511 surfcolor[1] = min(surfcolor[1], 1.0f);
3512 surfcolor[2] = min(surfcolor[2], 1.0f);
3513 VectorMultiply(shotcolor, surfcolor, shotcolor);
3514 if (VectorLength2(shotcolor) <= bounceminimumintensity2)
3516 r_refdef.stats[r_stat_bouncegrid_bounces]++;
3517 if (settings.bounceanglediffuse)
3519 // random direction, primarily along plane normal
3520 s = VectorDistance(cliptrace.endpos, clipend);
3521 VectorMA(cliptrace.plane.normal, 0.95f, bouncerandom[bouncecount], clipend);
3522 VectorNormalize(clipend);
3523 VectorScale(clipend, s, clipend);
3527 // reflect the remaining portion of the line across plane normal
3528 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
3529 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
3531 // calculate the new line start and end
3532 VectorCopy(cliptrace.endpos, clipstart);
3533 VectorAdd(clipstart, clipend, clipend);
3539 void R_Shadow_UpdateBounceGridTexture(void)
3541 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3542 r_shadow_bouncegrid_settings_t settings;
3543 qboolean enable = false;
3544 qboolean settingschanged;
3545 unsigned int range; // number of world lights
3546 unsigned int range1; // number of dynamic lights (or zero if disabled)
3547 unsigned int range2; // range+range1
3549 enable = R_Shadow_BounceGrid_CheckEnable(flag);
3551 R_Shadow_BounceGrid_GenerateSettings(&settings);
3553 // changing intensity does not require an update
3554 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
3556 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
3558 // when settings change, we free everything as it is just simpler that way.
3559 if (settingschanged || !enable)
3561 // not enabled, make sure we free anything we don't need anymore.
3562 if (r_shadow_bouncegrid_state.texture)
3564 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3565 r_shadow_bouncegrid_state.texture = NULL;
3567 r_shadow_bouncegrid_state.highpixels = NULL;
3568 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
3569 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
3570 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
3571 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
3572 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
3573 r_shadow_bouncegrid_state.maxsplatpaths = 0;
3574 r_shadow_bouncegrid_state.numpixels = 0;
3575 r_shadow_bouncegrid_state.directional = false;
3581 // if all the settings seem identical to the previous update, return
3582 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
3585 // store the new settings
3586 r_shadow_bouncegrid_state.settings = settings;
3588 R_Shadow_BounceGrid_UpdateSpacing();
3590 // get the range of light numbers we'll be looping over:
3591 // range = static lights
3592 // range1 = dynamic lights (optional)
3593 // range2 = range + range1
3594 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3595 range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
3596 range2 = range + range1;
3598 // calculate weighting factors for distributing photons among the lights
3599 R_Shadow_BounceGrid_AssignPhotons(&settings, range, range1, range2, flag);
3601 // trace the photons from lights and accumulate illumination
3602 R_Shadow_BounceGrid_TracePhotons(settings, range, range1, range2, flag);
3604 // clear the texture
3605 R_Shadow_BounceGrid_ClearPixels();
3607 // accumulate the light splatting into texture
3608 R_Shadow_BounceGrid_PerformSplats();
3610 // apply a mild blur filter to the texture
3611 R_Shadow_BounceGrid_BlurPixels();
3613 // convert the pixels to lower precision and upload the texture
3614 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
3616 // after we compute the static lighting we don't need to keep the highpixels array around
3617 if (settings.staticmode)
3619 r_shadow_bouncegrid_state.highpixels = NULL;
3620 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
3621 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
3622 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
3623 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
3624 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
3625 r_shadow_bouncegrid_state.maxsplatpaths = 0;
3629 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
3631 R_Shadow_RenderMode_Reset();
3632 GL_BlendFunc(GL_ONE, GL_ONE);
3633 GL_DepthRange(0, 1);
3634 GL_DepthTest(r_showshadowvolumes.integer < 2);
3635 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
3636 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
3637 GL_CullFace(GL_NONE);
3638 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
3641 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
3643 R_Shadow_RenderMode_Reset();
3644 GL_BlendFunc(GL_ONE, GL_ONE);
3645 GL_DepthRange(0, 1);
3646 GL_DepthTest(r_showlighting.integer < 2);
3647 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
3649 GL_DepthFunc(GL_EQUAL);
3650 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
3651 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
3654 void R_Shadow_RenderMode_End(void)
3656 R_Shadow_RenderMode_Reset();
3657 R_Shadow_RenderMode_ActiveLight(NULL);
3659 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3660 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3663 int bboxedges[12][2] =
3682 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
3684 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
3686 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
3687 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
3688 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
3689 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
3692 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
3693 return true; // invisible
3694 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
3695 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
3696 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
3697 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
3698 r_refdef.stats[r_stat_lights_scissored]++;
3702 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
3705 const float *vertex3f;
3706 const float *normal3f;
3708 float dist, dot, distintensity, shadeintensity, v[3], n[3];
3709 switch (r_shadow_rendermode)
3711 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3712 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3713 if (VectorLength2(diffusecolor) > 0)
3715 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)
3717 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3718 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3719 if ((dot = DotProduct(n, v)) < 0)
3721 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3722 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
3725 VectorCopy(ambientcolor, color4f);
3726 if (r_refdef.fogenabled)
3729 f = RSurf_FogVertex(vertex3f);
3730 VectorScale(color4f, f, color4f);
3737 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3739 VectorCopy(ambientcolor, color4f);
3740 if (r_refdef.fogenabled)
3743 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3744 f = RSurf_FogVertex(vertex3f);
3745 VectorScale(color4f + 4*i, f, color4f);
3751 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3752 if (VectorLength2(diffusecolor) > 0)
3754 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)
3756 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3757 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3759 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3760 if ((dot = DotProduct(n, v)) < 0)
3762 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3763 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3764 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3765 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3769 color4f[0] = ambientcolor[0] * distintensity;
3770 color4f[1] = ambientcolor[1] * distintensity;
3771 color4f[2] = ambientcolor[2] * distintensity;
3773 if (r_refdef.fogenabled)
3776 f = RSurf_FogVertex(vertex3f);
3777 VectorScale(color4f, f, color4f);
3781 VectorClear(color4f);
3787 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3789 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3790 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3792 color4f[0] = ambientcolor[0] * distintensity;
3793 color4f[1] = ambientcolor[1] * distintensity;
3794 color4f[2] = ambientcolor[2] * distintensity;
3795 if (r_refdef.fogenabled)
3798 f = RSurf_FogVertex(vertex3f);
3799 VectorScale(color4f, f, color4f);
3803 VectorClear(color4f);
3808 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3809 if (VectorLength2(diffusecolor) > 0)
3811 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)
3813 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3814 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3816 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3817 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3818 if ((dot = DotProduct(n, v)) < 0)
3820 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3821 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3822 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3823 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3827 color4f[0] = ambientcolor[0] * distintensity;
3828 color4f[1] = ambientcolor[1] * distintensity;
3829 color4f[2] = ambientcolor[2] * distintensity;
3831 if (r_refdef.fogenabled)
3834 f = RSurf_FogVertex(vertex3f);
3835 VectorScale(color4f, f, color4f);
3839 VectorClear(color4f);
3845 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3847 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3848 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3850 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3851 color4f[0] = ambientcolor[0] * distintensity;
3852 color4f[1] = ambientcolor[1] * distintensity;
3853 color4f[2] = ambientcolor[2] * distintensity;
3854 if (r_refdef.fogenabled)
3857 f = RSurf_FogVertex(vertex3f);
3858 VectorScale(color4f, f, color4f);
3862 VectorClear(color4f);
3872 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3874 // used to display how many times a surface is lit for level design purposes
3875 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3876 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3880 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
3882 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3883 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
3887 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3894 int newnumtriangles;
3898 int maxtriangles = 1024;
3899 int newelements[1024*3];
3900 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3901 for (renders = 0;renders < 4;renders++)
3906 newnumtriangles = 0;
3908 // due to low fillrate on the cards this vertex lighting path is
3909 // designed for, we manually cull all triangles that do not
3910 // contain a lit vertex
3911 // this builds batches of triangles from multiple surfaces and
3912 // renders them at once
3913 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3915 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3917 if (newnumtriangles)
3919 newfirstvertex = min(newfirstvertex, e[0]);
3920 newlastvertex = max(newlastvertex, e[0]);
3924 newfirstvertex = e[0];
3925 newlastvertex = e[0];
3927 newfirstvertex = min(newfirstvertex, e[1]);
3928 newlastvertex = max(newlastvertex, e[1]);
3929 newfirstvertex = min(newfirstvertex, e[2]);
3930 newlastvertex = max(newlastvertex, e[2]);
3936 if (newnumtriangles >= maxtriangles)
3938 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3939 newnumtriangles = 0;
3945 if (newnumtriangles >= 1)
3947 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3950 // if we couldn't find any lit triangles, exit early
3953 // now reduce the intensity for the next overbright pass
3954 // we have to clamp to 0 here incase the drivers have improper
3955 // handling of negative colors
3956 // (some old drivers even have improper handling of >1 color)
3958 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3960 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3962 c[0] = max(0, c[0] - 1);
3963 c[1] = max(0, c[1] - 1);
3964 c[2] = max(0, c[2] - 1);
3976 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
3978 // OpenGL 1.1 path (anything)
3979 float ambientcolorbase[3], diffusecolorbase[3];
3980 float ambientcolorpants[3], diffusecolorpants[3];
3981 float ambientcolorshirt[3], diffusecolorshirt[3];
3982 const float *surfacecolor = rsurface.texture->dlightcolor;
3983 const float *surfacepants = rsurface.colormap_pantscolor;
3984 const float *surfaceshirt = rsurface.colormap_shirtcolor;
3985 rtexture_t *basetexture = rsurface.texture->basetexture;
3986 rtexture_t *pantstexture = rsurface.texture->pantstexture;
3987 rtexture_t *shirttexture = rsurface.texture->shirttexture;
3988 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3989 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3990 ambientscale *= 2 * r_refdef.view.colorscale;
3991 diffusescale *= 2 * r_refdef.view.colorscale;
3992 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3993 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3994 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3995 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3996 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3997 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
3998 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3999 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
4000 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4001 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
4002 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
4003 R_Mesh_TexBind(0, basetexture);
4004 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
4005 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
4006 switch(r_shadow_rendermode)
4008 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
4009 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
4010 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
4011 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
4012 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4014 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
4015 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
4016 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
4017 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
4018 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4020 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
4021 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
4022 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
4023 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
4024 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4026 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
4031 //R_Mesh_TexBind(0, basetexture);
4032 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
4035 R_Mesh_TexBind(0, pantstexture);
4036 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
4040 R_Mesh_TexBind(0, shirttexture);
4041 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
4045 extern cvar_t gl_lightmaps;
4046 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
4048 float ambientscale, diffusescale, specularscale;
4050 float lightcolor[3];
4051 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
4052 ambientscale = rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient;
4053 diffusescale = rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient);
4054 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
4055 if (!r_shadow_usenormalmap.integer)
4057 ambientscale += 1.0f * diffusescale;
4061 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
4063 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
4066 VectorNegate(lightcolor, lightcolor);
4067 GL_BlendEquationSubtract(true);
4069 RSurf_SetupDepthAndCulling();
4070 switch (r_shadow_rendermode)
4072 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
4073 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
4074 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
4076 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
4077 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
4079 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
4080 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
4081 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
4082 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
4083 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
4086 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
4090 GL_BlendEquationSubtract(false);
4093 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)
4095 matrix4x4_t tempmatrix = *matrix;
4096 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
4098 // if this light has been compiled before, free the associated data
4099 R_RTLight_Uncompile(rtlight);
4101 // clear it completely to avoid any lingering data
4102 memset(rtlight, 0, sizeof(*rtlight));
4104 // copy the properties
4105 rtlight->matrix_lighttoworld = tempmatrix;
4106 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
4107 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
4108 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
4109 VectorCopy(color, rtlight->color);
4110 rtlight->cubemapname[0] = 0;
4111 if (cubemapname && cubemapname[0])
4112 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
4113 rtlight->shadow = shadow;
4114 rtlight->corona = corona;
4115 rtlight->style = style;
4116 rtlight->isstatic = isstatic;
4117 rtlight->coronasizescale = coronasizescale;
4118 rtlight->ambientscale = ambientscale;
4119 rtlight->diffusescale = diffusescale;
4120 rtlight->specularscale = specularscale;
4121 rtlight->flags = flags;
4123 // compute derived data
4124 //rtlight->cullradius = rtlight->radius;
4125 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
4126 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
4127 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
4128 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
4129 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
4130 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
4131 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
4134 // compiles rtlight geometry
4135 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
4136 void R_RTLight_Compile(rtlight_t *rtlight)
4139 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
4140 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
4141 entity_render_t *ent = r_refdef.scene.worldentity;
4142 dp_model_t *model = r_refdef.scene.worldmodel;
4143 unsigned char *data;
4146 // compile the light
4147 rtlight->compiled = true;
4148 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
4149 rtlight->static_numleafs = 0;
4150 rtlight->static_numleafpvsbytes = 0;
4151 rtlight->static_leaflist = NULL;
4152 rtlight->static_leafpvs = NULL;
4153 rtlight->static_numsurfaces = 0;
4154 rtlight->static_surfacelist = NULL;
4155 rtlight->static_shadowmap_receivers = 0x3F;
4156 rtlight->static_shadowmap_casters = 0x3F;
4157 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
4158 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
4159 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
4160 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
4161 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
4162 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
4164 if (model && model->GetLightInfo)
4166 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
4167 r_shadow_compilingrtlight = rtlight;
4168 R_FrameData_SetMark();
4169 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);
4170 R_FrameData_ReturnToMark();
4171 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
4172 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
4173 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
4174 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
4175 rtlight->static_numsurfaces = numsurfaces;
4176 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
4177 rtlight->static_numleafs = numleafs;
4178 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
4179 rtlight->static_numleafpvsbytes = numleafpvsbytes;
4180 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
4181 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
4182 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
4183 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
4184 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
4185 if (rtlight->static_numsurfaces)
4186 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
4187 if (rtlight->static_numleafs)
4188 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
4189 if (rtlight->static_numleafpvsbytes)
4190 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
4191 if (rtlight->static_numshadowtrispvsbytes)
4192 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
4193 if (rtlight->static_numlighttrispvsbytes)
4194 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
4195 R_FrameData_SetMark();
4196 switch (rtlight->shadowmode)
4198 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4199 if (model->CompileShadowMap && rtlight->shadow)
4200 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
4203 if (model->CompileShadowVolume && rtlight->shadow)
4204 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
4207 R_FrameData_ReturnToMark();
4208 // now we're done compiling the rtlight
4209 r_shadow_compilingrtlight = NULL;
4213 // use smallest available cullradius - box radius or light radius
4214 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
4215 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
4217 shadowzpasstris = 0;
4218 if (rtlight->static_meshchain_shadow_zpass)
4219 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
4220 shadowzpasstris += mesh->numtriangles;
4222 shadowzfailtris = 0;
4223 if (rtlight->static_meshchain_shadow_zfail)
4224 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
4225 shadowzfailtris += mesh->numtriangles;
4228 if (rtlight->static_numlighttrispvsbytes)
4229 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
4230 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
4234 if (rtlight->static_numshadowtrispvsbytes)
4235 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
4236 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
4239 if (developer_extra.integer)
4240 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);
4243 void R_RTLight_Uncompile(rtlight_t *rtlight)
4245 if (rtlight->compiled)
4247 if (rtlight->static_meshchain_shadow_zpass)
4248 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
4249 rtlight->static_meshchain_shadow_zpass = NULL;
4250 if (rtlight->static_meshchain_shadow_zfail)
4251 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
4252 rtlight->static_meshchain_shadow_zfail = NULL;
4253 if (rtlight->static_meshchain_shadow_shadowmap)
4254 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
4255 rtlight->static_meshchain_shadow_shadowmap = NULL;
4256 // these allocations are grouped
4257 if (rtlight->static_surfacelist)
4258 Mem_Free(rtlight->static_surfacelist);
4259 rtlight->static_numleafs = 0;
4260 rtlight->static_numleafpvsbytes = 0;
4261 rtlight->static_leaflist = NULL;
4262 rtlight->static_leafpvs = NULL;
4263 rtlight->static_numsurfaces = 0;
4264 rtlight->static_surfacelist = NULL;
4265 rtlight->static_numshadowtrispvsbytes = 0;
4266 rtlight->static_shadowtrispvs = NULL;
4267 rtlight->static_numlighttrispvsbytes = 0;
4268 rtlight->static_lighttrispvs = NULL;
4269 rtlight->compiled = false;
4273 void R_Shadow_UncompileWorldLights(void)
4277 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4278 for (lightindex = 0;lightindex < range;lightindex++)
4280 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4283 R_RTLight_Uncompile(&light->rtlight);
4287 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
4291 // reset the count of frustum planes
4292 // see rtlight->cached_frustumplanes definition for how much this array
4294 rtlight->cached_numfrustumplanes = 0;
4296 if (r_trippy.integer)
4299 // haven't implemented a culling path for ortho rendering
4300 if (!r_refdef.view.useperspective)
4302 // check if the light is on screen and copy the 4 planes if it is
4303 for (i = 0;i < 4;i++)
4304 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4307 for (i = 0;i < 4;i++)
4308 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4313 // generate a deformed frustum that includes the light origin, this is
4314 // used to cull shadow casting surfaces that can not possibly cast a
4315 // shadow onto the visible light-receiving surfaces, which can be a
4318 // if the light origin is onscreen the result will be 4 planes exactly
4319 // if the light origin is offscreen on only one axis the result will
4320 // be exactly 5 planes (split-side case)
4321 // if the light origin is offscreen on two axes the result will be
4322 // exactly 4 planes (stretched corner case)
4323 for (i = 0;i < 4;i++)
4325 // quickly reject standard frustum planes that put the light
4326 // origin outside the frustum
4327 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4330 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4332 // if all the standard frustum planes were accepted, the light is onscreen
4333 // otherwise we need to generate some more planes below...
4334 if (rtlight->cached_numfrustumplanes < 4)
4336 // at least one of the stock frustum planes failed, so we need to
4337 // create one or two custom planes to enclose the light origin
4338 for (i = 0;i < 4;i++)
4340 // create a plane using the view origin and light origin, and a
4341 // single point from the frustum corner set
4342 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
4343 VectorNormalize(plane.normal);
4344 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
4345 // see if this plane is backwards and flip it if so
4346 for (j = 0;j < 4;j++)
4347 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4351 VectorNegate(plane.normal, plane.normal);
4353 // flipped plane, test again to see if it is now valid
4354 for (j = 0;j < 4;j++)
4355 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4357 // if the plane is still not valid, then it is dividing the
4358 // frustum and has to be rejected
4362 // we have created a valid plane, compute extra info
4363 PlaneClassify(&plane);
4365 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4367 // if we've found 5 frustum planes then we have constructed a
4368 // proper split-side case and do not need to keep searching for
4369 // planes to enclose the light origin
4370 if (rtlight->cached_numfrustumplanes == 5)
4378 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
4380 plane = rtlight->cached_frustumplanes[i];
4381 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));
4386 // now add the light-space box planes if the light box is rotated, as any
4387 // caster outside the oriented light box is irrelevant (even if it passed
4388 // the worldspace light box, which is axial)
4389 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
4391 for (i = 0;i < 6;i++)
4395 v[i >> 1] = (i & 1) ? -1 : 1;
4396 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
4397 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
4398 plane.dist = VectorNormalizeLength(plane.normal);
4399 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
4400 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4406 // add the world-space reduced box planes
4407 for (i = 0;i < 6;i++)
4409 VectorClear(plane.normal);
4410 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
4411 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
4412 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4421 // reduce all plane distances to tightly fit the rtlight cull box, which
4423 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4424 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4425 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4426 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4427 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4428 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4429 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4430 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4431 oldnum = rtlight->cached_numfrustumplanes;
4432 rtlight->cached_numfrustumplanes = 0;
4433 for (j = 0;j < oldnum;j++)
4435 // find the nearest point on the box to this plane
4436 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
4437 for (i = 1;i < 8;i++)
4439 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
4440 if (bestdist > dist)
4443 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);
4444 // if the nearest point is near or behind the plane, we want this
4445 // plane, otherwise the plane is useless as it won't cull anything
4446 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
4448 PlaneClassify(&rtlight->cached_frustumplanes[j]);
4449 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
4456 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
4460 RSurf_ActiveWorldEntity();
4462 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4465 GL_CullFace(GL_NONE);
4466 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
4467 for (;mesh;mesh = mesh->next)
4469 if (!mesh->sidetotals[r_shadow_shadowmapside])
4471 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
4472 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4473 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);
4477 else if (r_refdef.scene.worldentity->model)
4478 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);
4480 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4483 static void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
4485 qboolean zpass = false;
4488 int surfacelistindex;
4489 msurface_t *surface;
4491 // if triangle neighbors are disabled, shadowvolumes are disabled
4492 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
4495 RSurf_ActiveWorldEntity();
4497 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4500 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
4502 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
4503 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
4505 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
4506 for (;mesh;mesh = mesh->next)
4508 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->numtriangles;
4509 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4510 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
4512 // increment stencil if frontface is infront of depthbuffer
4513 GL_CullFace(r_refdef.view.cullface_back);
4514 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
4515 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);
4516 // decrement stencil if backface is infront of depthbuffer
4517 GL_CullFace(r_refdef.view.cullface_front);
4518 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
4520 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
4522 // decrement stencil if backface is behind depthbuffer
4523 GL_CullFace(r_refdef.view.cullface_front);
4524 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
4525 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);
4526 // increment stencil if frontface is behind depthbuffer
4527 GL_CullFace(r_refdef.view.cullface_back);
4528 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
4530 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);
4534 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
4536 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
4537 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
4538 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
4540 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
4541 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
4542 if (CHECKPVSBIT(trispvs, t))
4543 shadowmarklist[numshadowmark++] = t;
4545 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);
4547 else if (numsurfaces)
4549 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);
4552 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4555 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
4557 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
4558 vec_t relativeshadowradius;
4559 RSurf_ActiveModelEntity(ent, false, false, false);
4560 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
4561 // we need to re-init the shader for each entity because the matrix changed
4562 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
4563 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
4564 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
4565 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
4566 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
4567 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
4568 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
4569 switch (r_shadow_rendermode)
4571 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
4572 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4575 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4578 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4581 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
4583 // set up properties for rendering light onto this entity
4584 RSurf_ActiveModelEntity(ent, true, true, false);
4585 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
4586 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4587 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4588 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4591 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
4593 if (!r_refdef.scene.worldmodel->DrawLight)
4596 // set up properties for rendering light onto this entity
4597 RSurf_ActiveWorldEntity();
4598 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
4599 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4600 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4601 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4603 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
4605 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4608 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
4610 dp_model_t *model = ent->model;
4611 if (!model->DrawLight)
4614 R_Shadow_SetupEntityLight(ent);
4616 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
4618 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4621 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
4625 int numleafs, numsurfaces;
4626 int *leaflist, *surfacelist;
4627 unsigned char *leafpvs;
4628 unsigned char *shadowtrispvs;
4629 unsigned char *lighttrispvs;
4630 //unsigned char *surfacesides;
4631 int numlightentities;
4632 int numlightentities_noselfshadow;
4633 int numshadowentities;
4634 int numshadowentities_noselfshadow;
4635 // FIXME: bounds check lightentities and shadowentities, etc.
4636 static entity_render_t *lightentities[MAX_EDICTS];
4637 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
4638 static entity_render_t *shadowentities[MAX_EDICTS];
4639 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
4641 qboolean castshadows;
4643 rtlight->draw = false;
4644 rtlight->cached_numlightentities = 0;
4645 rtlight->cached_numlightentities_noselfshadow = 0;
4646 rtlight->cached_numshadowentities = 0;
4647 rtlight->cached_numshadowentities_noselfshadow = 0;
4648 rtlight->cached_numsurfaces = 0;
4649 rtlight->cached_lightentities = NULL;
4650 rtlight->cached_lightentities_noselfshadow = NULL;
4651 rtlight->cached_shadowentities = NULL;
4652 rtlight->cached_shadowentities_noselfshadow = NULL;
4653 rtlight->cached_shadowtrispvs = NULL;
4654 rtlight->cached_lighttrispvs = NULL;
4655 rtlight->cached_surfacelist = NULL;
4656 rtlight->shadowmapsidesize = 0;
4658 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
4659 // skip lights that are basically invisible (color 0 0 0)
4660 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
4662 // loading is done before visibility checks because loading should happen
4663 // all at once at the start of a level, not when it stalls gameplay.
4664 // (especially important to benchmarks)
4666 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
4668 if (rtlight->compiled)
4669 R_RTLight_Uncompile(rtlight);
4670 R_RTLight_Compile(rtlight);
4674 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
4676 // look up the light style value at this time
4677 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4678 VectorScale(rtlight->color, f, rtlight->currentcolor);
4680 if (rtlight->selected)
4682 f = 2 + sin(realtime * M_PI * 4.0);
4683 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
4687 // skip if lightstyle is currently off
4688 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
4691 // skip processing on corona-only lights
4695 // skip if the light box is not touching any visible leafs
4696 if (r_shadow_culllights_pvs.integer
4697 && r_refdef.scene.worldmodel
4698 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
4699 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, rtlight->cullmins, rtlight->cullmaxs))
4702 // skip if the light box is not visible to traceline
4703 if (r_shadow_culllights_trace.integer)
4705 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))
4706 rtlight->trace_timer = realtime;
4707 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
4711 // skip if the light box is off screen
4712 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
4715 // in the typical case this will be quickly replaced by GetLightInfo
4716 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
4717 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
4719 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4721 // 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
4722 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
4725 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
4727 // compiled light, world available and can receive realtime lighting
4728 // retrieve leaf information
4729 numleafs = rtlight->static_numleafs;
4730 leaflist = rtlight->static_leaflist;
4731 leafpvs = rtlight->static_leafpvs;
4732 numsurfaces = rtlight->static_numsurfaces;
4733 surfacelist = rtlight->static_surfacelist;
4734 //surfacesides = NULL;
4735 shadowtrispvs = rtlight->static_shadowtrispvs;
4736 lighttrispvs = rtlight->static_lighttrispvs;
4738 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4740 // dynamic light, world available and can receive realtime lighting
4741 // calculate lit surfaces and leafs
4742 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);
4743 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4744 leaflist = r_shadow_buffer_leaflist;
4745 leafpvs = r_shadow_buffer_leafpvs;
4746 surfacelist = r_shadow_buffer_surfacelist;
4747 //surfacesides = r_shadow_buffer_surfacesides;
4748 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4749 lighttrispvs = r_shadow_buffer_lighttrispvs;
4750 // if the reduced leaf bounds are offscreen, skip it
4751 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4762 //surfacesides = NULL;
4763 shadowtrispvs = NULL;
4764 lighttrispvs = NULL;
4766 // check if light is illuminating any visible leafs
4769 for (i = 0; i < numleafs; i++)
4770 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4776 // make a list of lit entities and shadow casting entities
4777 numlightentities = 0;
4778 numlightentities_noselfshadow = 0;
4779 numshadowentities = 0;
4780 numshadowentities_noselfshadow = 0;
4782 // add dynamic entities that are lit by the light
4783 for (i = 0; i < r_refdef.scene.numentities; i++)
4786 entity_render_t *ent = r_refdef.scene.entities[i];
4788 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4790 // skip the object entirely if it is not within the valid
4791 // shadow-casting region (which includes the lit region)
4792 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
4794 if (!(model = ent->model))
4796 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4798 // this entity wants to receive light, is visible, and is
4799 // inside the light box
4800 // TODO: check if the surfaces in the model can receive light
4801 // so now check if it's in a leaf seen by the light
4802 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))
4804 if (ent->flags & RENDER_NOSELFSHADOW)
4805 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
4807 lightentities[numlightentities++] = ent;
4808 // since it is lit, it probably also casts a shadow...
4809 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4810 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4811 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4813 // note: exterior models without the RENDER_NOSELFSHADOW
4814 // flag still create a RENDER_NOSELFSHADOW shadow but
4815 // are lit normally, this means that they are
4816 // self-shadowing but do not shadow other
4817 // RENDER_NOSELFSHADOW entities such as the gun
4818 // (very weird, but keeps the player shadow off the gun)
4819 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4820 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4822 shadowentities[numshadowentities++] = ent;
4825 else if (ent->flags & RENDER_SHADOW)
4827 // this entity is not receiving light, but may still need to
4829 // TODO: check if the surfaces in the model can cast shadow
4830 // now check if it is in a leaf seen by the light
4831 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))
4833 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4834 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4835 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4837 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4838 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4840 shadowentities[numshadowentities++] = ent;
4845 // return if there's nothing at all to light
4846 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4849 // count this light in the r_speeds
4850 r_refdef.stats[r_stat_lights]++;
4852 // flag it as worth drawing later
4853 rtlight->draw = true;
4855 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
4856 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4858 numshadowentities = numshadowentities_noselfshadow = 0;
4859 rtlight->castshadows = castshadows;
4861 // cache all the animated entities that cast a shadow but are not visible
4862 for (i = 0; i < numshadowentities; i++)
4863 R_AnimCache_GetEntity(shadowentities[i], false, false);
4864 for (i = 0; i < numshadowentities_noselfshadow; i++)
4865 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4867 // 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)
4868 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
4870 for (i = 0; i < numshadowentities_noselfshadow; i++)
4871 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
4872 numshadowentities_noselfshadow = 0;
4875 // we can convert noselfshadow to regular if there are no casters of that type
4876 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
4878 for (i = 0; i < numlightentities_noselfshadow; i++)
4879 lightentities[numlightentities++] = lightentities_noselfshadow[i];
4880 numlightentities_noselfshadow = 0;
4883 // allocate some temporary memory for rendering this light later in the frame
4884 // reusable buffers need to be copied, static data can be used as-is
4885 rtlight->cached_numlightentities = numlightentities;
4886 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
4887 rtlight->cached_numshadowentities = numshadowentities;
4888 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4889 rtlight->cached_numsurfaces = numsurfaces;
4890 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4891 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4892 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4893 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4894 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4896 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4897 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4898 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4899 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4900 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4904 // compiled light data
4905 rtlight->cached_shadowtrispvs = shadowtrispvs;
4906 rtlight->cached_lighttrispvs = lighttrispvs;
4907 rtlight->cached_surfacelist = surfacelist;
4910 if (R_Shadow_ShadowMappingEnabled())
4912 // figure out the shadowmapping parameters for this light
4913 vec3_t nearestpoint;
4916 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4917 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4918 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4919 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4920 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
4921 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4922 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4923 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4924 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
4928 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
4932 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4933 int numlightentities;
4934 int numlightentities_noselfshadow;
4935 int numshadowentities;
4936 int numshadowentities_noselfshadow;
4937 entity_render_t **lightentities;
4938 entity_render_t **lightentities_noselfshadow;
4939 entity_render_t **shadowentities;
4940 entity_render_t **shadowentities_noselfshadow;
4942 static unsigned char entitysides[MAX_EDICTS];
4943 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4949 matrix4x4_t radiustolight;
4951 // check if we cached this light this frame (meaning it is worth drawing)
4952 if (!rtlight->draw || !rtlight->castshadows)
4955 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
4956 if (rtlight->shadowmapatlassidesize == 0)
4958 rtlight->castshadows = false;
4962 // set up a scissor rectangle for this light
4963 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4966 // don't let sound skip if going slow
4967 if (r_refdef.scene.extraupdate)
4970 numlightentities = rtlight->cached_numlightentities;
4971 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4972 numshadowentities = rtlight->cached_numshadowentities;
4973 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4974 numsurfaces = rtlight->cached_numsurfaces;
4975 lightentities = rtlight->cached_lightentities;
4976 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4977 shadowentities = rtlight->cached_shadowentities;
4978 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4979 shadowtrispvs = rtlight->cached_shadowtrispvs;
4980 lighttrispvs = rtlight->cached_lighttrispvs;
4981 surfacelist = rtlight->cached_surfacelist;
4983 // make this the active rtlight for rendering purposes
4984 R_Shadow_RenderMode_ActiveLight(rtlight);
4986 radiustolight = rtlight->matrix_worldtolight;
4987 Matrix4x4_Abs(&radiustolight);
4989 size = rtlight->shadowmapatlassidesize;
4990 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4992 surfacesides = NULL;
4997 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4999 castermask = rtlight->static_shadowmap_casters;
5000 receivermask = rtlight->static_shadowmap_receivers;
5004 surfacesides = r_shadow_buffer_surfacesides;
5005 for (i = 0; i < numsurfaces; i++)
5007 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
5008 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
5009 castermask |= surfacesides[i];
5010 receivermask |= surfacesides[i];
5015 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
5016 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
5017 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
5018 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
5020 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
5024 for (i = 0; i < numshadowentities; i++)
5025 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
5026 for (i = 0; i < numshadowentities_noselfshadow; i++)
5027 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
5030 // there is no need to render shadows for sides that have no receivers...
5031 castermask &= receivermask;
5033 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
5035 // render shadow casters into shadowmaps for this light
5036 for (side = 0; side < 6; side++)
5038 int bit = 1 << side;
5039 if (castermask & bit)
5041 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
5043 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
5044 for (i = 0; i < numshadowentities; i++)
5045 if (entitysides[i] & bit)
5046 R_Shadow_DrawEntityShadow(shadowentities[i]);
5047 for (i = 0; i < numshadowentities_noselfshadow; i++)
5048 if (entitysides_noselfshadow[i] & bit)
5049 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5052 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
5053 if (numshadowentities_noselfshadow)
5055 for (side = 0; side < 6; side++)
5057 int bit = 1 << side;
5058 if (castermask & bit)
5060 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
5062 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
5063 for (i = 0; i < numshadowentities; i++)
5064 if (entitysides[i] & bit)
5065 R_Shadow_DrawEntityShadow(shadowentities[i]);
5071 static void R_Shadow_DrawLight(rtlight_t *rtlight)
5075 unsigned char *shadowtrispvs, *lighttrispvs;
5076 int numlightentities;
5077 int numlightentities_noselfshadow;
5078 int numshadowentities;
5079 int numshadowentities_noselfshadow;
5080 entity_render_t **lightentities;
5081 entity_render_t **lightentities_noselfshadow;
5082 entity_render_t **shadowentities;
5083 entity_render_t **shadowentities_noselfshadow;
5085 qboolean castshadows;
5087 // check if we cached this light this frame (meaning it is worth drawing)
5091 // set up a scissor rectangle for this light
5092 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
5095 // don't let sound skip if going slow
5096 if (r_refdef.scene.extraupdate)
5099 numlightentities = rtlight->cached_numlightentities;
5100 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
5101 numshadowentities = rtlight->cached_numshadowentities;
5102 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
5103 numsurfaces = rtlight->cached_numsurfaces;
5104 lightentities = rtlight->cached_lightentities;
5105 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
5106 shadowentities = rtlight->cached_shadowentities;
5107 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
5108 shadowtrispvs = rtlight->cached_shadowtrispvs;
5109 lighttrispvs = rtlight->cached_lighttrispvs;
5110 surfacelist = rtlight->cached_surfacelist;
5111 castshadows = rtlight->castshadows;
5113 // make this the active rtlight for rendering purposes
5114 R_Shadow_RenderMode_ActiveLight(rtlight);
5116 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
5118 // optionally draw visible shape of the shadow volumes
5119 // for performance analysis by level designers
5120 R_Shadow_RenderMode_VisibleShadowVolumes();
5122 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
5123 for (i = 0;i < numshadowentities;i++)
5124 R_Shadow_DrawEntityShadow(shadowentities[i]);
5125 for (i = 0;i < numshadowentities_noselfshadow;i++)
5126 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5127 R_Shadow_RenderMode_VisibleLighting(false, false);
5130 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
5132 // optionally draw the illuminated areas
5133 // for performance analysis by level designers
5134 R_Shadow_RenderMode_VisibleLighting(false, false);
5136 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5137 for (i = 0;i < numlightentities;i++)
5138 R_Shadow_DrawEntityLight(lightentities[i]);
5139 for (i = 0;i < numlightentities_noselfshadow;i++)
5140 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5143 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
5147 float shadowmapoffsetnoselfshadow = 0;
5148 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
5149 Matrix4x4_Abs(&radiustolight);
5151 size = rtlight->shadowmapatlassidesize;
5152 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
5154 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
5156 if (rtlight->cached_numshadowentities_noselfshadow)
5157 shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
5159 // render lighting using the depth texture as shadowmap
5160 // draw lighting in the unmasked areas
5161 if (numsurfaces + numlightentities)
5163 R_Shadow_RenderMode_Lighting(false, false, true, false);
5164 // draw lighting in the unmasked areas
5166 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5167 for (i = 0; i < numlightentities; i++)
5168 R_Shadow_DrawEntityLight(lightentities[i]);
5170 // offset to the noselfshadow part of the atlas and draw those too
5171 if (numlightentities_noselfshadow)
5173 R_Shadow_RenderMode_Lighting(false, false, true, true);
5174 for (i = 0; i < numlightentities_noselfshadow; i++)
5175 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5178 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5179 if (r_shadow_usingdeferredprepass)
5180 R_Shadow_RenderMode_DrawDeferredLight(true);
5182 else if (castshadows && vid.stencil)
5184 // draw stencil shadow volumes to mask off pixels that are in shadow
5185 // so that they won't receive lighting
5186 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
5187 R_Shadow_ClearStencil();
5190 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
5191 for (i = 0;i < numshadowentities;i++)
5192 R_Shadow_DrawEntityShadow(shadowentities[i]);
5194 // draw lighting in the unmasked areas
5195 R_Shadow_RenderMode_Lighting(true, false, false, false);
5196 for (i = 0;i < numlightentities_noselfshadow;i++)
5197 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5199 for (i = 0;i < numshadowentities_noselfshadow;i++)
5200 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5202 // draw lighting in the unmasked areas
5203 R_Shadow_RenderMode_Lighting(true, false, false, false);
5205 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5206 for (i = 0;i < numlightentities;i++)
5207 R_Shadow_DrawEntityLight(lightentities[i]);
5209 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5210 if (r_shadow_usingdeferredprepass)
5211 R_Shadow_RenderMode_DrawDeferredLight(false);
5215 // draw lighting in the unmasked areas
5216 R_Shadow_RenderMode_Lighting(false, false, false, false);
5218 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5219 for (i = 0;i < numlightentities;i++)
5220 R_Shadow_DrawEntityLight(lightentities[i]);
5221 for (i = 0;i < numlightentities_noselfshadow;i++)
5222 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5224 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5225 if (r_shadow_usingdeferredprepass)
5226 R_Shadow_RenderMode_DrawDeferredLight(false);
5230 static void R_Shadow_FreeDeferred(void)
5232 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
5233 r_shadow_prepassgeometryfbo = 0;
5235 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
5236 r_shadow_prepasslightingdiffusespecularfbo = 0;
5238 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
5239 r_shadow_prepasslightingdiffusefbo = 0;
5241 if (r_shadow_prepassgeometrydepthbuffer)
5242 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
5243 r_shadow_prepassgeometrydepthbuffer = NULL;
5245 if (r_shadow_prepassgeometrynormalmaptexture)
5246 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
5247 r_shadow_prepassgeometrynormalmaptexture = NULL;
5249 if (r_shadow_prepasslightingdiffusetexture)
5250 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
5251 r_shadow_prepasslightingdiffusetexture = NULL;
5253 if (r_shadow_prepasslightingspeculartexture)
5254 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
5255 r_shadow_prepasslightingspeculartexture = NULL;
5258 void R_Shadow_DrawPrepass(void)
5262 entity_render_t *ent;
5263 float clearcolor[4];
5265 R_Mesh_ResetTextureState();
5267 GL_ColorMask(1,1,1,1);
5268 GL_BlendFunc(GL_ONE, GL_ZERO);
5271 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5272 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
5273 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
5274 if (r_timereport_active)
5275 R_TimeReport("prepasscleargeom");
5277 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
5278 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
5279 if (r_timereport_active)
5280 R_TimeReport("prepassworld");
5282 for (i = 0;i < r_refdef.scene.numentities;i++)
5284 if (!r_refdef.viewcache.entityvisible[i])
5286 ent = r_refdef.scene.entities[i];
5287 if (ent->model && ent->model->DrawPrepass != NULL)
5288 ent->model->DrawPrepass(ent);
5291 if (r_timereport_active)
5292 R_TimeReport("prepassmodels");
5294 GL_DepthMask(false);
5295 GL_ColorMask(1,1,1,1);
5298 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5299 Vector4Set(clearcolor, 0, 0, 0, 0);
5300 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
5301 if (r_timereport_active)
5302 R_TimeReport("prepassclearlit");
5304 R_Shadow_RenderMode_Begin();
5306 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5307 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5309 R_Shadow_RenderMode_End();
5311 if (r_timereport_active)
5312 R_TimeReport("prepasslights");
5315 #define MAX_SCENELIGHTS 65536
5316 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
5318 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
5320 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
5322 r_shadow_scenemaxlights *= 2;
5323 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
5324 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
5326 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
5330 void R_Shadow_DrawLightSprites(void);
5331 void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
5340 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
5341 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
5342 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
5344 if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
5345 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
5346 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
5347 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
5348 r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) ||
5349 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
5350 r_shadow_shadowmapborder != shadowmapborder ||
5351 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
5352 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
5353 R_Shadow_FreeShadowMaps();
5355 r_shadow_fb_fbo = fbo;
5356 r_shadow_fb_depthtexture = depthtexture;
5357 r_shadow_fb_colortexture = colortexture;
5359 r_shadow_usingshadowmaportho = false;
5361 switch (vid.renderpath)
5363 case RENDERPATH_GL20:
5364 case RENDERPATH_D3D9:
5365 case RENDERPATH_D3D10:
5366 case RENDERPATH_D3D11:
5367 case RENDERPATH_SOFT:
5369 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
5371 r_shadow_usingdeferredprepass = false;
5372 if (r_shadow_prepass_width)
5373 R_Shadow_FreeDeferred();
5374 r_shadow_prepass_width = r_shadow_prepass_height = 0;
5378 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
5380 R_Shadow_FreeDeferred();
5382 r_shadow_usingdeferredprepass = true;
5383 r_shadow_prepass_width = vid.width;
5384 r_shadow_prepass_height = vid.height;
5385 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
5386 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);
5387 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);
5388 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);
5390 // set up the geometry pass fbo (depth + normalmap)
5391 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5392 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5393 // render depth into a renderbuffer and other important properties into the normalmap texture
5395 // set up the lighting pass fbo (diffuse + specular)
5396 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5397 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5398 // render diffuse into one texture and specular into another,
5399 // with depth and normalmap bound as textures,
5400 // with depth bound as attachment as well
5402 // set up the lighting pass fbo (diffuse)
5403 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5404 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5405 // render diffuse into one texture,
5406 // with depth and normalmap bound as textures,
5407 // with depth bound as attachment as well
5411 case RENDERPATH_GL11:
5412 case RENDERPATH_GL13:
5413 case RENDERPATH_GLES1:
5414 case RENDERPATH_GLES2:
5415 r_shadow_usingdeferredprepass = false;
5419 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);
5421 r_shadow_scenenumlights = 0;
5422 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5423 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5424 for (lightindex = 0; lightindex < range; lightindex++)
5426 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5427 if (light && (light->flags & flag))
5429 R_Shadow_PrepareLight(&light->rtlight);
5430 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5433 if (r_refdef.scene.rtdlight)
5435 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5437 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
5438 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
5441 else if (gl_flashblend.integer)
5443 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5445 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
5446 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
5447 VectorScale(rtlight->color, f, rtlight->currentcolor);
5451 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
5452 if (r_shadow_debuglight.integer >= 0)
5454 r_shadow_scenenumlights = 0;
5455 lightindex = r_shadow_debuglight.integer;
5456 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5459 R_Shadow_PrepareLight(&light->rtlight);
5460 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5464 // if we're doing shadowmaps we need to prepare the atlas layout now
5465 if (R_Shadow_ShadowMappingEnabled())
5469 // allocate shadowmaps in the atlas now
5470 // 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...
5471 for (lod = 0; lod < 16; lod++)
5473 int packing_success = 0;
5474 int packing_failure = 0;
5475 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
5476 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
5477 if (r_shadow_shadowmapatlas_modelshadows_size)
5478 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);
5479 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5481 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
5482 int size = rtlight->shadowmapsidesize >> lod;
5484 if (!rtlight->castshadows)
5486 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
5489 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
5490 if (rtlight->cached_numshadowentities_noselfshadow)
5492 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
5494 rtlight->shadowmapatlassidesize = size;
5499 // note down that we failed to pack this one, it will have to disable shadows
5500 rtlight->shadowmapatlassidesize = 0;
5504 // generally everything fits and we stop here on the first iteration
5505 if (packing_failure == 0)
5510 if (r_editlights.integer)
5511 R_Shadow_DrawLightSprites();
5514 void R_Shadow_DrawShadowMaps(void)
5516 R_Shadow_RenderMode_Begin();
5517 R_Shadow_RenderMode_ActiveLight(NULL);
5519 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
5520 R_Shadow_ClearShadowMapTexture();
5522 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
5523 if (r_shadow_shadowmapatlas_modelshadows_size)
5525 R_Shadow_DrawModelShadowMaps();
5526 // don't let sound skip if going slow
5527 if (r_refdef.scene.extraupdate)
5531 if (R_Shadow_ShadowMappingEnabled())
5534 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5535 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
5538 R_Shadow_RenderMode_End();
5541 void R_Shadow_DrawLights(void)
5545 R_Shadow_RenderMode_Begin();
5547 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5548 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5550 R_Shadow_RenderMode_End();
5553 #define MAX_MODELSHADOWS 1024
5554 static int r_shadow_nummodelshadows;
5555 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
5557 void R_Shadow_PrepareModelShadows(void)
5560 float scale, size, radius, dot1, dot2;
5561 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5562 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
5563 entity_render_t *ent;
5565 r_shadow_nummodelshadows = 0;
5566 r_shadow_shadowmapatlas_modelshadows_size = 0;
5568 if (!r_refdef.scene.numentities || r_refdef.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
5571 switch (r_shadow_shadowmode)
5573 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
5574 if (r_shadows.integer >= 2)
5577 case R_SHADOW_SHADOWMODE_STENCIL:
5580 for (i = 0; i < r_refdef.scene.numentities; i++)
5582 ent = r_refdef.scene.entities[i];
5583 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5585 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5587 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5588 R_AnimCache_GetEntity(ent, false, false);
5596 size = 2 * r_shadow_shadowmapmaxsize;
5597 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
5598 radius = 0.5f * size / scale;
5600 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5601 VectorCopy(prvmshadowdir, shadowdir);
5602 VectorNormalize(shadowdir);
5603 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5604 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5605 if (fabs(dot1) <= fabs(dot2))
5606 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5608 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5609 VectorNormalize(shadowforward);
5610 CrossProduct(shadowdir, shadowforward, shadowright);
5611 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5612 VectorCopy(prvmshadowfocus, shadowfocus);
5613 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5614 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5615 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5616 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5617 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5619 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5621 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5622 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5623 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5624 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5625 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5626 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5628 for (i = 0; i < r_refdef.scene.numentities; i++)
5630 ent = r_refdef.scene.entities[i];
5631 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
5633 // cast shadows from anything of the map (submodels are optional)
5634 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5636 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5638 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5639 R_AnimCache_GetEntity(ent, false, false);
5643 if (r_shadow_nummodelshadows)
5645 r_shadow_shadowmapatlas_modelshadows_x = 0;
5646 r_shadow_shadowmapatlas_modelshadows_y = 0;
5647 r_shadow_shadowmapatlas_modelshadows_size = size;
5651 static void R_Shadow_DrawModelShadowMaps(void)
5654 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
5655 entity_render_t *ent;
5656 vec3_t relativelightorigin;
5657 vec3_t relativelightdirection, relativeforward, relativeright;
5658 vec3_t relativeshadowmins, relativeshadowmaxs;
5659 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
5660 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5662 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
5663 r_viewport_t viewport;
5665 size = r_shadow_shadowmapatlas_modelshadows_size;
5666 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
5667 radius = 0.5f / scale;
5668 nearclip = -r_shadows_throwdistance.value;
5669 farclip = r_shadows_throwdistance.value;
5670 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);
5672 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
5673 r_shadow_modelshadowmap_parameters[0] = size;
5674 r_shadow_modelshadowmap_parameters[1] = size;
5675 r_shadow_modelshadowmap_parameters[2] = 1.0;
5676 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
5677 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
5678 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
5679 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
5680 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
5681 r_shadow_usingshadowmaportho = true;
5683 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5684 VectorCopy(prvmshadowdir, shadowdir);
5685 VectorNormalize(shadowdir);
5686 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5687 VectorCopy(prvmshadowfocus, shadowfocus);
5688 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5689 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5690 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5691 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5692 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5693 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5694 if (fabs(dot1) <= fabs(dot2))
5695 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5697 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5698 VectorNormalize(shadowforward);
5699 VectorM(scale, shadowforward, &m[0]);
5700 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5702 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
5703 CrossProduct(shadowdir, shadowforward, shadowright);
5704 VectorM(scale, shadowright, &m[4]);
5705 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
5706 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
5707 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
5708 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
5709 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
5710 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);
5711 R_SetViewport(&viewport);
5713 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5715 // render into a slightly restricted region so that the borders of the
5716 // shadowmap area fade away, rather than streaking across everything
5717 // outside the usable area
5718 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
5720 for (i = 0;i < r_shadow_nummodelshadows;i++)
5722 ent = r_shadow_modelshadows[i];
5723 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5724 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
5725 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5726 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
5727 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
5728 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5729 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5730 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5731 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5732 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5733 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5734 RSurf_ActiveModelEntity(ent, false, false, false);
5735 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
5736 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5742 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
5744 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
5746 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
5747 Cvar_SetValueQuick(&r_test, 0);
5752 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
5753 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
5754 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
5755 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
5756 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
5757 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
5759 switch (vid.renderpath)
5761 case RENDERPATH_GL11:
5762 case RENDERPATH_GL13:
5763 case RENDERPATH_GL20:
5764 case RENDERPATH_SOFT:
5765 case RENDERPATH_GLES1:
5766 case RENDERPATH_GLES2:
5768 case RENDERPATH_D3D9:
5769 case RENDERPATH_D3D10:
5770 case RENDERPATH_D3D11:
5771 #ifdef MATRIX4x4_OPENGLORIENTATION
5772 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5773 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
5774 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
5775 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
5777 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5778 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
5779 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
5780 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
5786 void R_Shadow_DrawModelShadows(void)
5789 float relativethrowdistance;
5790 entity_render_t *ent;
5791 vec3_t relativelightorigin;
5792 vec3_t relativelightdirection;
5793 vec3_t relativeshadowmins, relativeshadowmaxs;
5794 vec3_t tmp, shadowdir;
5795 prvm_vec3_t prvmshadowdir;
5797 if (!r_shadow_nummodelshadows || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
5800 R_ResetViewRendering3D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5801 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
5802 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5803 R_Shadow_RenderMode_Begin();
5804 R_Shadow_RenderMode_ActiveLight(NULL);
5805 r_shadow_lightscissor[0] = r_refdef.view.x;
5806 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
5807 r_shadow_lightscissor[2] = r_refdef.view.width;
5808 r_shadow_lightscissor[3] = r_refdef.view.height;
5809 R_Shadow_RenderMode_StencilShadowVolumes(false);
5812 if (r_shadows.integer == 2)
5814 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5815 VectorCopy(prvmshadowdir, shadowdir);
5816 VectorNormalize(shadowdir);
5819 R_Shadow_ClearStencil();
5821 for (i = 0;i < r_shadow_nummodelshadows;i++)
5823 ent = r_shadow_modelshadows[i];
5825 // cast shadows from anything of the map (submodels are optional)
5826 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5827 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
5828 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
5829 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
5830 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5833 if(ent->entitynumber != 0)
5835 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
5837 // FIXME handle this
5838 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5842 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
5843 int entnum, entnum2, recursion;
5844 entnum = entnum2 = ent->entitynumber;
5845 for(recursion = 32; recursion > 0; --recursion)
5847 entnum2 = cl.entities[entnum].state_current.tagentity;
5848 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
5853 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
5855 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
5856 // transform into modelspace of OUR entity
5857 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
5858 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
5861 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5865 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5868 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
5869 RSurf_ActiveModelEntity(ent, false, false, false);
5870 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
5871 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5874 // not really the right mode, but this will disable any silly stencil features
5875 R_Shadow_RenderMode_End();
5877 // set up ortho view for rendering this pass
5878 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5879 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5880 //GL_ScissorTest(true);
5881 //R_EntityMatrix(&identitymatrix);
5882 //R_Mesh_ResetTextureState();
5883 R_ResetViewRendering2D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5885 // set up a darkening blend on shadowed areas
5886 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5887 //GL_DepthRange(0, 1);
5888 //GL_DepthTest(false);
5889 //GL_DepthMask(false);
5890 //GL_PolygonOffset(0, 0);CHECKGLERROR
5891 GL_Color(0, 0, 0, r_shadows_darken.value);
5892 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5893 //GL_DepthFunc(GL_ALWAYS);
5894 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5896 // apply the blend to the shadowed areas
5897 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5898 R_SetupShader_Generic_NoTexture(false, true);
5899 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5901 // restore the viewport
5902 R_SetViewport(&r_refdef.view.viewport);
5904 // restore other state to normal
5905 //R_Shadow_RenderMode_End();
5908 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5911 vec3_t centerorigin;
5912 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5915 // if it's too close, skip it
5916 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5918 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5921 if (usequery && r_numqueries + 2 <= r_maxqueries)
5923 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5924 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5925 // 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
5926 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5928 switch(vid.renderpath)
5930 case RENDERPATH_GL11:
5931 case RENDERPATH_GL13:
5932 case RENDERPATH_GL20:
5933 case RENDERPATH_GLES1:
5934 case RENDERPATH_GLES2:
5935 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5937 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5938 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5939 GL_DepthFunc(GL_ALWAYS);
5940 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5941 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5942 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5943 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5944 GL_DepthFunc(GL_LEQUAL);
5945 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5946 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5947 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5948 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5949 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5953 case RENDERPATH_D3D9:
5954 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5956 case RENDERPATH_D3D10:
5957 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5959 case RENDERPATH_D3D11:
5960 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5962 case RENDERPATH_SOFT:
5963 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5967 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5970 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5972 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5975 unsigned int occlude = 0;
5976 GLint allpixels = 0, visiblepixels = 0;
5978 // now we have to check the query result
5979 if (rtlight->corona_queryindex_visiblepixels)
5981 switch(vid.renderpath)
5983 case RENDERPATH_GL20:
5984 case RENDERPATH_GLES1:
5985 case RENDERPATH_GLES2:
5986 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5987 // See if we can use the GPU-side method to prevent implicit sync
5988 if (vid.support.arb_query_buffer_object) {
5989 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
5990 if (!r_shadow_occlusion_buf) {
5991 qglGenBuffersARB(1, &r_shadow_occlusion_buf);
5992 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5993 qglBufferDataARB(GL_QUERY_BUFFER_ARB, 8, NULL, GL_DYNAMIC_COPY);
5995 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5997 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(0));
5998 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4));
5999 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
6000 occlude = MATERIALFLAG_OCCLUDE;
6001 cscale *= rtlight->corona_visibility;
6009 case RENDERPATH_GL11:
6010 case RENDERPATH_GL13:
6011 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
6013 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
6014 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
6015 if (visiblepixels < 1 || allpixels < 1)
6017 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
6018 cscale *= rtlight->corona_visibility;
6024 case RENDERPATH_D3D9:
6025 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6027 case RENDERPATH_D3D10:
6028 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6030 case RENDERPATH_D3D11:
6031 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6033 case RENDERPATH_SOFT:
6034 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6042 // FIXME: these traces should scan all render entities instead of cl.world
6043 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
6046 VectorScale(rtlight->currentcolor, cscale, color);
6047 if (VectorLength(color) > (1.0f / 256.0f))
6050 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
6053 VectorNegate(color, color);
6054 GL_BlendEquationSubtract(true);
6056 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
6057 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);
6058 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
6060 GL_BlendEquationSubtract(false);
6064 void R_Shadow_DrawCoronas(void)
6067 qboolean usequery = false;
6072 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
6074 if (r_fb.water.renderingscene)
6076 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6077 R_EntityMatrix(&identitymatrix);
6079 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6081 // check occlusion of coronas
6082 // use GL_ARB_occlusion_query if available
6083 // otherwise use raytraces
6085 switch (vid.renderpath)
6087 case RENDERPATH_GL11:
6088 case RENDERPATH_GL13:
6089 case RENDERPATH_GL20:
6090 case RENDERPATH_GLES1:
6091 case RENDERPATH_GLES2:
6092 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
6093 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
6096 GL_ColorMask(0,0,0,0);
6097 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
6098 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
6101 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
6102 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
6104 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
6107 RSurf_ActiveWorldEntity();
6108 GL_BlendFunc(GL_ONE, GL_ZERO);
6109 GL_CullFace(GL_NONE);
6110 GL_DepthMask(false);
6111 GL_DepthRange(0, 1);
6112 GL_PolygonOffset(0, 0);
6114 R_Mesh_ResetTextureState();
6115 R_SetupShader_Generic_NoTexture(false, false);
6119 case RENDERPATH_D3D9:
6121 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6123 case RENDERPATH_D3D10:
6124 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6126 case RENDERPATH_D3D11:
6127 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6129 case RENDERPATH_SOFT:
6131 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6134 for (lightindex = 0;lightindex < range;lightindex++)
6136 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6139 rtlight = &light->rtlight;
6140 rtlight->corona_visibility = 0;
6141 rtlight->corona_queryindex_visiblepixels = 0;
6142 rtlight->corona_queryindex_allpixels = 0;
6143 if (!(rtlight->flags & flag))
6145 if (rtlight->corona <= 0)
6147 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
6149 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6151 for (i = 0;i < r_refdef.scene.numlights;i++)
6153 rtlight = r_refdef.scene.lights[i];
6154 rtlight->corona_visibility = 0;
6155 rtlight->corona_queryindex_visiblepixels = 0;
6156 rtlight->corona_queryindex_allpixels = 0;
6157 if (!(rtlight->flags & flag))
6159 if (rtlight->corona <= 0)
6161 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6164 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
6166 // now draw the coronas using the query data for intensity info
6167 for (lightindex = 0;lightindex < range;lightindex++)
6169 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6172 rtlight = &light->rtlight;
6173 if (rtlight->corona_visibility <= 0)
6175 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6177 for (i = 0;i < r_refdef.scene.numlights;i++)
6179 rtlight = r_refdef.scene.lights[i];
6180 if (rtlight->corona_visibility <= 0)
6182 if (gl_flashblend.integer)
6183 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
6185 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6191 static dlight_t *R_Shadow_NewWorldLight(void)
6193 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
6196 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)
6200 // 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
6202 // validate parameters
6206 // copy to light properties
6207 VectorCopy(origin, light->origin);
6208 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
6209 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
6210 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
6212 light->color[0] = max(color[0], 0);
6213 light->color[1] = max(color[1], 0);
6214 light->color[2] = max(color[2], 0);
6216 light->color[0] = color[0];
6217 light->color[1] = color[1];
6218 light->color[2] = color[2];
6219 light->radius = max(radius, 0);
6220 light->style = style;
6221 light->shadow = shadowenable;
6222 light->corona = corona;
6223 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
6224 light->coronasizescale = coronasizescale;
6225 light->ambientscale = ambientscale;
6226 light->diffusescale = diffusescale;
6227 light->specularscale = specularscale;
6228 light->flags = flags;
6230 // update renderable light data
6231 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
6232 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);
6235 static void R_Shadow_FreeWorldLight(dlight_t *light)
6237 if (r_shadow_selectedlight == light)
6238 r_shadow_selectedlight = NULL;
6239 R_RTLight_Uncompile(&light->rtlight);
6240 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
6243 void R_Shadow_ClearWorldLights(void)
6247 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6248 for (lightindex = 0;lightindex < range;lightindex++)
6250 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6252 R_Shadow_FreeWorldLight(light);
6254 r_shadow_selectedlight = NULL;
6257 static void R_Shadow_SelectLight(dlight_t *light)
6259 if (r_shadow_selectedlight)
6260 r_shadow_selectedlight->selected = false;
6261 r_shadow_selectedlight = light;
6262 if (r_shadow_selectedlight)
6263 r_shadow_selectedlight->selected = true;
6266 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6268 // this is never batched (there can be only one)
6270 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
6271 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6272 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6275 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6280 skinframe_t *skinframe;
6283 // this is never batched (due to the ent parameter changing every time)
6284 // so numsurfaces == 1 and surfacelist[0] == lightnumber
6285 const dlight_t *light = (dlight_t *)ent;
6288 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
6291 VectorScale(light->color, intensity, spritecolor);
6292 if (VectorLength(spritecolor) < 0.1732f)
6293 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
6294 if (VectorLength(spritecolor) > 1.0f)
6295 VectorNormalize(spritecolor);
6297 // draw light sprite
6298 if (light->cubemapname[0] && !light->shadow)
6299 skinframe = r_editlights_sprcubemapnoshadowlight;
6300 else if (light->cubemapname[0])
6301 skinframe = r_editlights_sprcubemaplight;
6302 else if (!light->shadow)
6303 skinframe = r_editlights_sprnoshadowlight;
6305 skinframe = r_editlights_sprlight;
6307 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);
6308 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6310 // draw selection sprite if light is selected
6311 if (light->selected)
6313 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6314 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6315 // VorteX todo: add normalmode/realtime mode light overlay sprites?
6319 void R_Shadow_DrawLightSprites(void)
6323 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6324 for (lightindex = 0;lightindex < range;lightindex++)
6326 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6328 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
6330 if (!r_editlights_lockcursor)
6331 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
6334 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
6339 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6340 if (lightindex >= range)
6342 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6345 rtlight = &light->rtlight;
6346 //if (!(rtlight->flags & flag))
6348 VectorCopy(rtlight->shadoworigin, origin);
6349 *radius = rtlight->radius;
6350 VectorCopy(rtlight->color, color);
6354 static void R_Shadow_SelectLightInView(void)
6356 float bestrating, rating, temp[3];
6360 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6364 if (r_editlights_lockcursor)
6366 for (lightindex = 0;lightindex < range;lightindex++)
6368 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6371 VectorSubtract(light->origin, r_refdef.view.origin, temp);
6372 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
6375 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
6376 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1.0f)
6378 bestrating = rating;
6383 R_Shadow_SelectLight(best);
6386 void R_Shadow_LoadWorldLights(void)
6388 int n, a, style, shadow, flags;
6389 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
6390 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
6391 if (cl.worldmodel == NULL)
6393 Con_Print("No map loaded.\n");
6396 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6397 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6407 for (;COM_Parse(t, true) && strcmp(
6408 if (COM_Parse(t, true))
6410 if (com_token[0] == '!')
6413 origin[0] = atof(com_token+1);
6416 origin[0] = atof(com_token);
6421 while (*s && *s != '\n' && *s != '\r')
6427 // check for modifier flags
6434 #if _MSC_VER >= 1400
6435 #define sscanf sscanf_s
6437 cubemapname[sizeof(cubemapname)-1] = 0;
6438 #if MAX_QPATH != 128
6439 #error update this code if MAX_QPATH changes
6441 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
6442 #if _MSC_VER >= 1400
6443 , sizeof(cubemapname)
6445 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
6448 flags = LIGHTFLAG_REALTIMEMODE;
6456 coronasizescale = 0.25f;
6458 VectorClear(angles);
6461 if (a < 9 || !strcmp(cubemapname, "\"\""))
6463 // remove quotes on cubemapname
6464 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
6467 namelen = strlen(cubemapname) - 2;
6468 memmove(cubemapname, cubemapname + 1, namelen);
6469 cubemapname[namelen] = '\0';
6473 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);
6476 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6484 Con_Printf("invalid rtlights file \"%s\"\n", name);
6485 Mem_Free(lightsstring);
6489 void R_Shadow_SaveWorldLights(void)
6493 size_t bufchars, bufmaxchars;
6495 char name[MAX_QPATH];
6496 char line[MAX_INPUTLINE];
6497 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
6498 // I hate lines which are 3 times my screen size :( --blub
6501 if (cl.worldmodel == NULL)
6503 Con_Print("No map loaded.\n");
6506 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6507 bufchars = bufmaxchars = 0;
6509 for (lightindex = 0;lightindex < range;lightindex++)
6511 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6514 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
6515 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);
6516 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
6517 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]);
6519 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);
6520 if (bufchars + strlen(line) > bufmaxchars)
6522 bufmaxchars = bufchars + strlen(line) + 2048;
6524 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
6528 memcpy(buf, oldbuf, bufchars);
6534 memcpy(buf + bufchars, line, strlen(line));
6535 bufchars += strlen(line);
6539 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
6544 void R_Shadow_LoadLightsFile(void)
6547 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
6548 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
6549 if (cl.worldmodel == NULL)
6551 Con_Print("No map loaded.\n");
6554 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
6555 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6563 while (*s && *s != '\n' && *s != '\r')
6569 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);
6573 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);
6576 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
6577 radius = bound(15, radius, 4096);
6578 VectorScale(color, (2.0f / (8388608.0f)), color);
6579 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6587 Con_Printf("invalid lights file \"%s\"\n", name);
6588 Mem_Free(lightsstring);
6592 // tyrlite/hmap2 light types in the delay field
6593 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
6595 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
6607 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
6608 char key[256], value[MAX_INPUTLINE];
6611 if (cl.worldmodel == NULL)
6613 Con_Print("No map loaded.\n");
6616 // try to load a .ent file first
6617 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
6618 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
6619 // and if that is not found, fall back to the bsp file entity string
6621 data = cl.worldmodel->brush.entities;
6624 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
6626 type = LIGHTTYPE_MINUSX;
6627 origin[0] = origin[1] = origin[2] = 0;
6628 originhack[0] = originhack[1] = originhack[2] = 0;
6629 angles[0] = angles[1] = angles[2] = 0;
6630 color[0] = color[1] = color[2] = 1;
6631 light[0] = light[1] = light[2] = 1;light[3] = 300;
6632 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
6642 if (!COM_ParseToken_Simple(&data, false, false, true))
6644 if (com_token[0] == '}')
6645 break; // end of entity
6646 if (com_token[0] == '_')
6647 strlcpy(key, com_token + 1, sizeof(key));
6649 strlcpy(key, com_token, sizeof(key));
6650 while (key[strlen(key)-1] == ' ') // remove trailing spaces
6651 key[strlen(key)-1] = 0;
6652 if (!COM_ParseToken_Simple(&data, false, false, true))
6654 strlcpy(value, com_token, sizeof(value));
6656 // now that we have the key pair worked out...
6657 if (!strcmp("light", key))
6659 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
6663 light[0] = vec[0] * (1.0f / 256.0f);
6664 light[1] = vec[0] * (1.0f / 256.0f);
6665 light[2] = vec[0] * (1.0f / 256.0f);
6671 light[0] = vec[0] * (1.0f / 255.0f);
6672 light[1] = vec[1] * (1.0f / 255.0f);
6673 light[2] = vec[2] * (1.0f / 255.0f);
6677 else if (!strcmp("delay", key))
6679 else if (!strcmp("origin", key))
6680 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
6681 else if (!strcmp("angle", key))
6682 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
6683 else if (!strcmp("angles", key))
6684 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
6685 else if (!strcmp("color", key))
6686 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
6687 else if (!strcmp("wait", key))
6688 fadescale = atof(value);
6689 else if (!strcmp("classname", key))
6691 if (!strncmp(value, "light", 5))
6694 if (!strcmp(value, "light_fluoro"))
6699 overridecolor[0] = 1;
6700 overridecolor[1] = 1;
6701 overridecolor[2] = 1;
6703 if (!strcmp(value, "light_fluorospark"))
6708 overridecolor[0] = 1;
6709 overridecolor[1] = 1;
6710 overridecolor[2] = 1;
6712 if (!strcmp(value, "light_globe"))
6717 overridecolor[0] = 1;
6718 overridecolor[1] = 0.8;
6719 overridecolor[2] = 0.4;
6721 if (!strcmp(value, "light_flame_large_yellow"))
6726 overridecolor[0] = 1;
6727 overridecolor[1] = 0.5;
6728 overridecolor[2] = 0.1;
6730 if (!strcmp(value, "light_flame_small_yellow"))
6735 overridecolor[0] = 1;
6736 overridecolor[1] = 0.5;
6737 overridecolor[2] = 0.1;
6739 if (!strcmp(value, "light_torch_small_white"))
6744 overridecolor[0] = 1;
6745 overridecolor[1] = 0.5;
6746 overridecolor[2] = 0.1;
6748 if (!strcmp(value, "light_torch_small_walltorch"))
6753 overridecolor[0] = 1;
6754 overridecolor[1] = 0.5;
6755 overridecolor[2] = 0.1;
6759 else if (!strcmp("style", key))
6760 style = atoi(value);
6761 else if (!strcmp("skin", key))
6762 skin = (int)atof(value);
6763 else if (!strcmp("pflags", key))
6764 pflags = (int)atof(value);
6765 //else if (!strcmp("effects", key))
6766 // effects = (int)atof(value);
6767 else if (cl.worldmodel->type == mod_brushq3)
6769 if (!strcmp("scale", key))
6770 lightscale = atof(value);
6771 if (!strcmp("fade", key))
6772 fadescale = atof(value);
6777 if (lightscale <= 0)
6781 if (color[0] == color[1] && color[0] == color[2])
6783 color[0] *= overridecolor[0];
6784 color[1] *= overridecolor[1];
6785 color[2] *= overridecolor[2];
6787 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
6788 color[0] = color[0] * light[0];
6789 color[1] = color[1] * light[1];
6790 color[2] = color[2] * light[2];
6793 case LIGHTTYPE_MINUSX:
6795 case LIGHTTYPE_RECIPX:
6797 VectorScale(color, (1.0f / 16.0f), color);
6799 case LIGHTTYPE_RECIPXX:
6801 VectorScale(color, (1.0f / 16.0f), color);
6804 case LIGHTTYPE_NONE:
6808 case LIGHTTYPE_MINUSXX:
6811 VectorAdd(origin, originhack, origin);
6813 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);
6816 Mem_Free(entfiledata);
6820 static void R_Shadow_SetCursorLocationForView(void)
6823 vec3_t dest, endpos;
6825 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
6826 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true);
6827 if (trace.fraction < 1)
6829 dist = trace.fraction * r_editlights_cursordistance.value;
6830 push = r_editlights_cursorpushback.value;
6834 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
6835 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
6839 VectorClear( endpos );
6841 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6842 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6843 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6846 void R_Shadow_UpdateWorldLightSelection(void)
6848 if (r_editlights.integer)
6850 R_Shadow_SetCursorLocationForView();
6851 R_Shadow_SelectLightInView();
6854 R_Shadow_SelectLight(NULL);
6857 static void R_Shadow_EditLights_Clear_f(void)
6859 R_Shadow_ClearWorldLights();
6862 void R_Shadow_EditLights_Reload_f(void)
6866 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
6867 R_Shadow_ClearWorldLights();
6868 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
6870 R_Shadow_LoadWorldLights();
6871 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6872 R_Shadow_LoadLightsFile();
6874 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
6876 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6877 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6881 static void R_Shadow_EditLights_Save_f(void)
6885 R_Shadow_SaveWorldLights();
6888 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6890 R_Shadow_ClearWorldLights();
6891 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6894 static void R_Shadow_EditLights_ImportLightsFile_f(void)
6896 R_Shadow_ClearWorldLights();
6897 R_Shadow_LoadLightsFile();
6900 static void R_Shadow_EditLights_Spawn_f(void)
6903 if (!r_editlights.integer)
6905 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6908 if (Cmd_Argc() != 1)
6910 Con_Print("r_editlights_spawn does not take parameters\n");
6913 color[0] = color[1] = color[2] = 1;
6914 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6917 static void R_Shadow_EditLights_Edit_f(void)
6919 vec3_t origin, angles, color;
6920 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6921 int style, shadows, flags, normalmode, realtimemode;
6922 char cubemapname[MAX_INPUTLINE];
6923 if (!r_editlights.integer)
6925 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6928 if (!r_shadow_selectedlight)
6930 Con_Print("No selected light.\n");
6933 VectorCopy(r_shadow_selectedlight->origin, origin);
6934 VectorCopy(r_shadow_selectedlight->angles, angles);
6935 VectorCopy(r_shadow_selectedlight->color, color);
6936 radius = r_shadow_selectedlight->radius;
6937 style = r_shadow_selectedlight->style;
6938 if (r_shadow_selectedlight->cubemapname)
6939 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6942 shadows = r_shadow_selectedlight->shadow;
6943 corona = r_shadow_selectedlight->corona;
6944 coronasizescale = r_shadow_selectedlight->coronasizescale;
6945 ambientscale = r_shadow_selectedlight->ambientscale;
6946 diffusescale = r_shadow_selectedlight->diffusescale;
6947 specularscale = r_shadow_selectedlight->specularscale;
6948 flags = r_shadow_selectedlight->flags;
6949 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6950 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6951 if (!strcmp(Cmd_Argv(1), "origin"))
6953 if (Cmd_Argc() != 5)
6955 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6958 origin[0] = atof(Cmd_Argv(2));
6959 origin[1] = atof(Cmd_Argv(3));
6960 origin[2] = atof(Cmd_Argv(4));
6962 else if (!strcmp(Cmd_Argv(1), "originscale"))
6964 if (Cmd_Argc() != 5)
6966 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6969 origin[0] *= atof(Cmd_Argv(2));
6970 origin[1] *= atof(Cmd_Argv(3));
6971 origin[2] *= atof(Cmd_Argv(4));
6973 else if (!strcmp(Cmd_Argv(1), "originx"))
6975 if (Cmd_Argc() != 3)
6977 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6980 origin[0] = atof(Cmd_Argv(2));
6982 else if (!strcmp(Cmd_Argv(1), "originy"))
6984 if (Cmd_Argc() != 3)
6986 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6989 origin[1] = atof(Cmd_Argv(2));
6991 else if (!strcmp(Cmd_Argv(1), "originz"))
6993 if (Cmd_Argc() != 3)
6995 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6998 origin[2] = atof(Cmd_Argv(2));
7000 else if (!strcmp(Cmd_Argv(1), "move"))
7002 if (Cmd_Argc() != 5)
7004 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
7007 origin[0] += atof(Cmd_Argv(2));
7008 origin[1] += atof(Cmd_Argv(3));
7009 origin[2] += atof(Cmd_Argv(4));
7011 else if (!strcmp(Cmd_Argv(1), "movex"))
7013 if (Cmd_Argc() != 3)
7015 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7018 origin[0] += atof(Cmd_Argv(2));
7020 else if (!strcmp(Cmd_Argv(1), "movey"))
7022 if (Cmd_Argc() != 3)
7024 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7027 origin[1] += atof(Cmd_Argv(2));
7029 else if (!strcmp(Cmd_Argv(1), "movez"))
7031 if (Cmd_Argc() != 3)
7033 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7036 origin[2] += atof(Cmd_Argv(2));
7038 else if (!strcmp(Cmd_Argv(1), "angles"))
7040 if (Cmd_Argc() != 5)
7042 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
7045 angles[0] = atof(Cmd_Argv(2));
7046 angles[1] = atof(Cmd_Argv(3));
7047 angles[2] = atof(Cmd_Argv(4));
7049 else if (!strcmp(Cmd_Argv(1), "anglesx"))
7051 if (Cmd_Argc() != 3)
7053 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7056 angles[0] = atof(Cmd_Argv(2));
7058 else if (!strcmp(Cmd_Argv(1), "anglesy"))
7060 if (Cmd_Argc() != 3)
7062 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7065 angles[1] = atof(Cmd_Argv(2));
7067 else if (!strcmp(Cmd_Argv(1), "anglesz"))
7069 if (Cmd_Argc() != 3)
7071 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7074 angles[2] = atof(Cmd_Argv(2));
7076 else if (!strcmp(Cmd_Argv(1), "color"))
7078 if (Cmd_Argc() != 5)
7080 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
7083 color[0] = atof(Cmd_Argv(2));
7084 color[1] = atof(Cmd_Argv(3));
7085 color[2] = atof(Cmd_Argv(4));
7087 else if (!strcmp(Cmd_Argv(1), "radius"))
7089 if (Cmd_Argc() != 3)
7091 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7094 radius = atof(Cmd_Argv(2));
7096 else if (!strcmp(Cmd_Argv(1), "colorscale"))
7098 if (Cmd_Argc() == 3)
7100 double scale = atof(Cmd_Argv(2));
7107 if (Cmd_Argc() != 5)
7109 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
7112 color[0] *= atof(Cmd_Argv(2));
7113 color[1] *= atof(Cmd_Argv(3));
7114 color[2] *= atof(Cmd_Argv(4));
7117 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
7119 if (Cmd_Argc() != 3)
7121 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7124 radius *= atof(Cmd_Argv(2));
7126 else if (!strcmp(Cmd_Argv(1), "style"))
7128 if (Cmd_Argc() != 3)
7130 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7133 style = atoi(Cmd_Argv(2));
7135 else if (!strcmp(Cmd_Argv(1), "cubemap"))
7139 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7142 if (Cmd_Argc() == 3)
7143 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
7147 else if (!strcmp(Cmd_Argv(1), "shadows"))
7149 if (Cmd_Argc() != 3)
7151 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7154 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7156 else if (!strcmp(Cmd_Argv(1), "corona"))
7158 if (Cmd_Argc() != 3)
7160 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7163 corona = atof(Cmd_Argv(2));
7165 else if (!strcmp(Cmd_Argv(1), "coronasize"))
7167 if (Cmd_Argc() != 3)
7169 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7172 coronasizescale = atof(Cmd_Argv(2));
7174 else if (!strcmp(Cmd_Argv(1), "ambient"))
7176 if (Cmd_Argc() != 3)
7178 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7181 ambientscale = atof(Cmd_Argv(2));
7183 else if (!strcmp(Cmd_Argv(1), "diffuse"))
7185 if (Cmd_Argc() != 3)
7187 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7190 diffusescale = atof(Cmd_Argv(2));
7192 else if (!strcmp(Cmd_Argv(1), "specular"))
7194 if (Cmd_Argc() != 3)
7196 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7199 specularscale = atof(Cmd_Argv(2));
7201 else if (!strcmp(Cmd_Argv(1), "normalmode"))
7203 if (Cmd_Argc() != 3)
7205 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7208 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7210 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
7212 if (Cmd_Argc() != 3)
7214 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7217 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7221 Con_Print("usage: r_editlights_edit [property] [value]\n");
7222 Con_Print("Selected light's properties:\n");
7223 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7224 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7225 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7226 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
7227 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
7228 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
7229 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
7230 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
7231 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
7232 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
7233 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
7234 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
7235 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
7236 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
7239 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
7240 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
7243 static void R_Shadow_EditLights_EditAll_f(void)
7246 dlight_t *light, *oldselected;
7249 if (!r_editlights.integer)
7251 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
7255 oldselected = r_shadow_selectedlight;
7256 // EditLights doesn't seem to have a "remove" command or something so:
7257 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7258 for (lightindex = 0;lightindex < range;lightindex++)
7260 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7263 R_Shadow_SelectLight(light);
7264 R_Shadow_EditLights_Edit_f();
7266 // return to old selected (to not mess editing once selection is locked)
7267 R_Shadow_SelectLight(oldselected);
7270 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
7272 int lightnumber, lightcount;
7273 size_t lightindex, range;
7278 if (!r_editlights.integer)
7281 // update cvars so QC can query them
7282 if (r_shadow_selectedlight)
7284 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7285 Cvar_SetQuick(&r_editlights_current_origin, temp);
7286 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7287 Cvar_SetQuick(&r_editlights_current_angles, temp);
7288 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7289 Cvar_SetQuick(&r_editlights_current_color, temp);
7290 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
7291 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
7292 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
7293 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
7294 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
7295 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
7296 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
7297 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
7298 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
7299 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
7300 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
7303 // draw properties on screen
7304 if (!r_editlights_drawproperties.integer)
7306 x = vid_conwidth.value - 320;
7308 DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
7311 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7312 for (lightindex = 0;lightindex < range;lightindex++)
7314 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7317 if (light == r_shadow_selectedlight)
7318 lightnumber = (int)lightindex;
7321 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;
7322 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;
7324 if (r_shadow_selectedlight == NULL)
7326 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;
7327 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;
7328 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;
7329 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;
7330 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;
7331 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;
7332 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;
7333 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;
7334 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;
7335 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;
7336 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;
7337 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;
7338 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;
7339 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;
7340 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;
7342 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;
7343 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;
7344 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;
7345 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;
7346 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;
7347 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;
7348 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;
7349 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;
7350 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;
7351 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;
7354 static void R_Shadow_EditLights_ToggleShadow_f(void)
7356 if (!r_editlights.integer)
7358 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7361 if (!r_shadow_selectedlight)
7363 Con_Print("No selected light.\n");
7366 R_Shadow_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);
7369 static void R_Shadow_EditLights_ToggleCorona_f(void)
7371 if (!r_editlights.integer)
7373 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7376 if (!r_shadow_selectedlight)
7378 Con_Print("No selected light.\n");
7381 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);
7384 static void R_Shadow_EditLights_Remove_f(void)
7386 if (!r_editlights.integer)
7388 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
7391 if (!r_shadow_selectedlight)
7393 Con_Print("No selected light.\n");
7396 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
7397 r_shadow_selectedlight = NULL;
7400 static void R_Shadow_EditLights_Help_f(void)
7403 "Documentation on r_editlights system:\n"
7405 "r_editlights : enable/disable editing mode\n"
7406 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
7407 "r_editlights_cursorpushback : push back cursor this far from surface\n"
7408 "r_editlights_cursorpushoff : push cursor off surface this far\n"
7409 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
7410 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
7412 "r_editlights_help : this help\n"
7413 "r_editlights_clear : remove all lights\n"
7414 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
7415 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
7416 "r_editlights_save : save to .rtlights file\n"
7417 "r_editlights_spawn : create a light with default settings\n"
7418 "r_editlights_edit command : edit selected light - more documentation below\n"
7419 "r_editlights_remove : remove selected light\n"
7420 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
7421 "r_editlights_importlightentitiesfrommap : reload light entities\n"
7422 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
7424 "origin x y z : set light location\n"
7425 "originx x: set x component of light location\n"
7426 "originy y: set y component of light location\n"
7427 "originz z: set z component of light location\n"
7428 "move x y z : adjust light location\n"
7429 "movex x: adjust x component of light location\n"
7430 "movey y: adjust y component of light location\n"
7431 "movez z: adjust z component of light location\n"
7432 "angles x y z : set light angles\n"
7433 "anglesx x: set x component of light angles\n"
7434 "anglesy y: set y component of light angles\n"
7435 "anglesz z: set z component of light angles\n"
7436 "color r g b : set color of light (can be brighter than 1 1 1)\n"
7437 "radius radius : set radius (size) of light\n"
7438 "colorscale grey : multiply color of light (1 does nothing)\n"
7439 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
7440 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
7441 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
7442 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
7443 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
7444 "cubemap basename : set filter cubemap of light\n"
7445 "shadows 1/0 : turn on/off shadows\n"
7446 "corona n : set corona intensity\n"
7447 "coronasize n : set corona size (0-1)\n"
7448 "ambient n : set ambient intensity (0-1)\n"
7449 "diffuse n : set diffuse intensity (0-1)\n"
7450 "specular n : set specular intensity (0-1)\n"
7451 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
7452 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
7453 "<nothing> : print light properties to console\n"
7457 static void R_Shadow_EditLights_CopyInfo_f(void)
7459 if (!r_editlights.integer)
7461 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
7464 if (!r_shadow_selectedlight)
7466 Con_Print("No selected light.\n");
7469 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
7470 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
7471 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
7472 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
7473 if (r_shadow_selectedlight->cubemapname)
7474 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
7476 r_shadow_bufferlight.cubemapname[0] = 0;
7477 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
7478 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
7479 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
7480 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
7481 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
7482 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
7483 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
7486 static void R_Shadow_EditLights_PasteInfo_f(void)
7488 if (!r_editlights.integer)
7490 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
7493 if (!r_shadow_selectedlight)
7495 Con_Print("No selected light.\n");
7498 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);
7501 static void R_Shadow_EditLights_Lock_f(void)
7503 if (!r_editlights.integer)
7505 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
7508 if (r_editlights_lockcursor)
7510 r_editlights_lockcursor = false;
7513 if (!r_shadow_selectedlight)
7515 Con_Print("No selected light to lock on.\n");
7518 r_editlights_lockcursor = true;
7521 static void R_Shadow_EditLights_Init(void)
7523 Cvar_RegisterVariable(&r_editlights);
7524 Cvar_RegisterVariable(&r_editlights_cursordistance);
7525 Cvar_RegisterVariable(&r_editlights_cursorpushback);
7526 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
7527 Cvar_RegisterVariable(&r_editlights_cursorgrid);
7528 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
7529 Cvar_RegisterVariable(&r_editlights_drawproperties);
7530 Cvar_RegisterVariable(&r_editlights_current_origin);
7531 Cvar_RegisterVariable(&r_editlights_current_angles);
7532 Cvar_RegisterVariable(&r_editlights_current_color);
7533 Cvar_RegisterVariable(&r_editlights_current_radius);
7534 Cvar_RegisterVariable(&r_editlights_current_corona);
7535 Cvar_RegisterVariable(&r_editlights_current_coronasize);
7536 Cvar_RegisterVariable(&r_editlights_current_style);
7537 Cvar_RegisterVariable(&r_editlights_current_shadows);
7538 Cvar_RegisterVariable(&r_editlights_current_cubemap);
7539 Cvar_RegisterVariable(&r_editlights_current_ambient);
7540 Cvar_RegisterVariable(&r_editlights_current_diffuse);
7541 Cvar_RegisterVariable(&r_editlights_current_specular);
7542 Cvar_RegisterVariable(&r_editlights_current_normalmode);
7543 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
7544 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
7545 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
7546 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)");
7547 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
7548 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
7549 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
7550 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)");
7551 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
7552 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
7553 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
7554 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
7555 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
7556 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
7557 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)");
7558 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
7564 =============================================================================
7568 =============================================================================
7571 void R_LightPoint(float *color, const vec3_t p, const int flags)
7573 int i, numlights, flag;
7574 float f, relativepoint[3], dist, dist2, lightradius2;
7579 if (r_fullbright.integer)
7581 VectorSet(color, 1, 1, 1);
7587 if (flags & LP_LIGHTMAP)
7589 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7591 VectorClear(diffuse);
7592 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, color, diffuse, n);
7593 VectorAdd(color, diffuse, color);
7596 VectorSet(color, 1, 1, 1);
7597 color[0] += r_refdef.scene.ambient;
7598 color[1] += r_refdef.scene.ambient;
7599 color[2] += r_refdef.scene.ambient;
7602 if (flags & LP_RTWORLD)
7604 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7605 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7606 for (i = 0; i < numlights; i++)
7608 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7611 light = &dlight->rtlight;
7612 if (!(light->flags & flag))
7615 lightradius2 = light->radius * light->radius;
7616 VectorSubtract(light->shadoworigin, p, relativepoint);
7617 dist2 = VectorLength2(relativepoint);
7618 if (dist2 >= lightradius2)
7620 dist = sqrt(dist2) / light->radius;
7621 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7624 // todo: add to both ambient and diffuse
7625 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1)
7626 VectorMA(color, f, light->currentcolor, color);
7629 if (flags & LP_DYNLIGHT)
7632 for (i = 0;i < r_refdef.scene.numlights;i++)
7634 light = r_refdef.scene.lights[i];
7636 lightradius2 = light->radius * light->radius;
7637 VectorSubtract(light->shadoworigin, p, relativepoint);
7638 dist2 = VectorLength2(relativepoint);
7639 if (dist2 >= lightradius2)
7641 dist = sqrt(dist2) / light->radius;
7642 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7645 // todo: add to both ambient and diffuse
7646 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1)
7647 VectorMA(color, f, light->color, color);
7652 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
7654 int i, numlights, flag;
7657 float relativepoint[3];
7666 if (r_fullbright.integer)
7668 VectorSet(ambient, 1, 1, 1);
7669 VectorClear(diffuse);
7670 VectorClear(lightdir);
7674 if (flags == LP_LIGHTMAP)
7676 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7677 VectorClear(diffuse);
7678 VectorClear(lightdir);
7679 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7680 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
7682 VectorSet(ambient, 1, 1, 1);
7686 memset(sample, 0, sizeof(sample));
7687 VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7689 if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7692 VectorClear(tempambient);
7694 VectorClear(relativepoint);
7695 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
7696 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
7697 VectorScale(color, r_refdef.lightmapintensity, color);
7698 VectorAdd(sample, tempambient, sample);
7699 VectorMA(sample , 0.5f , color, sample );
7700 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7701 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7702 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7703 // calculate a weighted average light direction as well
7704 intensity = VectorLength(color);
7705 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7708 if (flags & LP_RTWORLD)
7710 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7711 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7712 for (i = 0; i < numlights; i++)
7714 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7717 light = &dlight->rtlight;
7718 if (!(light->flags & flag))
7721 lightradius2 = light->radius * light->radius;
7722 VectorSubtract(light->shadoworigin, p, relativepoint);
7723 dist2 = VectorLength2(relativepoint);
7724 if (dist2 >= lightradius2)
7726 dist = sqrt(dist2) / light->radius;
7727 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
7728 if (intensity <= 0.0f)
7730 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
7732 // scale down intensity to add to both ambient and diffuse
7733 //intensity *= 0.5f;
7734 VectorNormalize(relativepoint);
7735 VectorScale(light->currentcolor, intensity, color);
7736 VectorMA(sample , 0.5f , color, sample );
7737 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7738 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7739 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7740 // calculate a weighted average light direction as well
7741 intensity *= VectorLength(color);
7742 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7744 // FIXME: sample bouncegrid too!
7747 if (flags & LP_DYNLIGHT)
7750 for (i = 0;i < r_refdef.scene.numlights;i++)
7752 light = r_refdef.scene.lights[i];
7754 lightradius2 = light->radius * light->radius;
7755 VectorSubtract(light->shadoworigin, p, relativepoint);
7756 dist2 = VectorLength2(relativepoint);
7757 if (dist2 >= lightradius2)
7759 dist = sqrt(dist2) / light->radius;
7760 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
7761 if (intensity <= 0.0f)
7763 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
7765 // scale down intensity to add to both ambient and diffuse
7766 //intensity *= 0.5f;
7767 VectorNormalize(relativepoint);
7768 VectorScale(light->currentcolor, intensity, color);
7769 VectorMA(sample , 0.5f , color, sample );
7770 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7771 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7772 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7773 // calculate a weighted average light direction as well
7774 intensity *= VectorLength(color);
7775 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7779 // calculate the direction we'll use to reduce the sample to a directional light source
7780 VectorCopy(sample + 12, dir);
7781 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
7782 VectorNormalize(dir);
7783 // extract the diffuse color along the chosen direction and scale it
7784 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
7785 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
7786 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
7787 // subtract some of diffuse from ambient
7788 VectorMA(sample, -0.333f, diffuse, ambient);
7789 // store the normalized lightdir
7790 VectorCopy(dir, lightdir);