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 int r_shadow_viewfbo;
273 rtexture_t *r_shadow_viewdepthtexture;
274 rtexture_t *r_shadow_viewcolortexture;
277 int r_shadow_viewwidth;
278 int r_shadow_viewheight;
280 // lights are reloaded when this changes
281 char r_shadow_mapname[MAX_QPATH];
283 // buffer for doing corona fading
284 unsigned int r_shadow_occlusion_buf = 0;
286 // used only for light filters (cubemaps)
287 rtexturepool_t *r_shadow_filters_texturepool;
289 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"};
290 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"};
291 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
292 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"};
293 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)"};
294 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
295 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)"};
296 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"};
297 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
298 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
299 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
300 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
301 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
302 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
303 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
304 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
305 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
306 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)"};
307 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
308 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
309 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
310 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
311 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)"};
312 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)"};
313 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"};
314 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
315 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
316 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"};
317 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)"};
318 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
319 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)"};
320 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "1", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes"};
321 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)"};
322 cvar_t r_shadow_shadowmapping_useshadowsampler = {CVAR_SAVE, "r_shadow_shadowmapping_useshadowsampler", "1", "whether to use sampler2DShadow if available"};
323 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
324 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
325 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"};
326 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..."};
327 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"};
328 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"};
329 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
330 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
331 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "5", "shadowmap size bias for filtering"};
332 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
333 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
334 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
335 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
336 cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
337 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
338 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)"};
339 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)"};
340 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"};
341 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"};
342 cvar_t r_shadow_culllights_trace_eyejitter = {CVAR_SAVE, "r_shadow_culllights_trace_eyejitter", "16", "offset eye location randomly by this much"};
343 cvar_t r_shadow_culllights_trace_enlarge = {CVAR_SAVE, "r_shadow_culllights_trace_enlarge", "0.1", "make light bounds bigger by *1.0+enlarge"};
344 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)"};
345 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)"};
346 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"};
347 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)"};
348 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"};
349 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"};
350 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" };
351 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)"};
352 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"};
353 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"};
354 cvar_t r_shadow_bouncegrid_dynamic_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
355 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)"};
356 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)"};
357 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"};
358 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)"};
359 cvar_t r_shadow_bouncegrid_dynamic_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_spacing", "64", "unit size of bouncegrid pixel"};
360 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"};
361 cvar_t r_shadow_bouncegrid_dynamic_x = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_x", "64", "maximum texture size of bouncegrid on X axis"};
362 cvar_t r_shadow_bouncegrid_dynamic_y = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_y", "64", "maximum texture size of bouncegrid on Y axis"};
363 cvar_t r_shadow_bouncegrid_dynamic_z = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_z", "32", "maximum texture size of bouncegrid on Z axis"};
364 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"};
365 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)"};
366 cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
367 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"};
368 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"};
369 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)" };
370 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"};
371 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "0.25", "brightness of particles contributing to bouncegrid texture"};
372 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" };
373 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)" };
374 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"};
375 cvar_t r_shadow_bouncegrid_static = {CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
376 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" };
377 cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
378 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"};
379 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"};
380 cvar_t r_shadow_bouncegrid_static_maxphotons = {CVAR_SAVE, "r_shadow_bouncegrid_static_maxphotons", "250000", "upper bound on photons in static mode"};
381 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)" };
382 cvar_t r_shadow_bouncegrid_static_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_static_spacing", "64", "unit size of bouncegrid pixel when in static mode"};
383 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
384 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"};
385 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!"};
386 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
387 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
388 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
389 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
390 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
391 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
392 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
393 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
394 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
395 cvar_t r_editlights_drawproperties = {0, "r_editlights_drawproperties", "1", "draw properties of currently selected light"};
396 cvar_t r_editlights_current_origin = {0, "r_editlights_current_origin", "0 0 0", "origin of selected light"};
397 cvar_t r_editlights_current_angles = {0, "r_editlights_current_angles", "0 0 0", "angles of selected light"};
398 cvar_t r_editlights_current_color = {0, "r_editlights_current_color", "1 1 1", "color of selected light"};
399 cvar_t r_editlights_current_radius = {0, "r_editlights_current_radius", "0", "radius of selected light"};
400 cvar_t r_editlights_current_corona = {0, "r_editlights_current_corona", "0", "corona intensity of selected light"};
401 cvar_t r_editlights_current_coronasize = {0, "r_editlights_current_coronasize", "0", "corona size of selected light"};
402 cvar_t r_editlights_current_style = {0, "r_editlights_current_style", "0", "style of selected light"};
403 cvar_t r_editlights_current_shadows = {0, "r_editlights_current_shadows", "0", "shadows flag of selected light"};
404 cvar_t r_editlights_current_cubemap = {0, "r_editlights_current_cubemap", "0", "cubemap of selected light"};
405 cvar_t r_editlights_current_ambient = {0, "r_editlights_current_ambient", "0", "ambient intensity of selected light"};
406 cvar_t r_editlights_current_diffuse = {0, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"};
407 cvar_t r_editlights_current_specular = {0, "r_editlights_current_specular", "1", "specular intensity of selected light"};
408 cvar_t r_editlights_current_normalmode = {0, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"};
409 cvar_t r_editlights_current_realtimemode = {0, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"};
411 r_shadow_bouncegrid_state_t r_shadow_bouncegrid_state;
413 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
414 #define ATTENTABLESIZE 256
415 // 1D gradient, 2D circle and 3D sphere attenuation textures
416 #define ATTEN1DSIZE 32
417 #define ATTEN2DSIZE 64
418 #define ATTEN3DSIZE 32
420 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
421 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
422 static float r_shadow_attentable[ATTENTABLESIZE+1];
424 rtlight_t *r_shadow_compilingrtlight;
425 static memexpandablearray_t r_shadow_worldlightsarray;
426 dlight_t *r_shadow_selectedlight;
427 dlight_t r_shadow_bufferlight;
428 vec3_t r_editlights_cursorlocation;
429 qboolean r_editlights_lockcursor;
431 extern int con_vislines;
433 void R_Shadow_UncompileWorldLights(void);
434 void R_Shadow_ClearWorldLights(void);
435 void R_Shadow_SaveWorldLights(void);
436 void R_Shadow_LoadWorldLights(void);
437 void R_Shadow_LoadLightsFile(void);
438 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
439 void R_Shadow_EditLights_Reload_f(void);
440 void R_Shadow_ValidateCvars(void);
441 static void R_Shadow_MakeTextures(void);
443 #define EDLIGHTSPRSIZE 8
444 skinframe_t *r_editlights_sprcursor;
445 skinframe_t *r_editlights_sprlight;
446 skinframe_t *r_editlights_sprnoshadowlight;
447 skinframe_t *r_editlights_sprcubemaplight;
448 skinframe_t *r_editlights_sprcubemapnoshadowlight;
449 skinframe_t *r_editlights_sprselection;
451 static void R_Shadow_DrawModelShadowMaps(void);
452 static void R_Shadow_MakeShadowMap(int texturesize);
453 static void R_Shadow_MakeVSDCT(void);
454 static void R_Shadow_SetShadowMode(void)
456 r_shadow_shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
457 r_shadow_shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
458 r_shadow_shadowmapmaxsize = bound(r_shadow_shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, r_shadow_shadowmaptexturesize / 8);
459 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
460 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
461 r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
462 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
463 r_shadow_shadowmapsampler = false;
464 r_shadow_shadowmappcf = 0;
465 r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
466 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
467 Mod_AllocLightmap_Init(&r_shadow_shadowmapatlas_state, r_main_mempool, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize);
468 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
470 switch(vid.renderpath)
472 case RENDERPATH_GL20:
473 if(r_shadow_shadowmapfilterquality < 0)
475 if (!r_fb.usedepthtextures)
476 r_shadow_shadowmappcf = 1;
477 else if((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && vid.support.arb_shadow && r_shadow_shadowmapshadowsampler)
479 r_shadow_shadowmapsampler = true;
480 r_shadow_shadowmappcf = 1;
482 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
483 r_shadow_shadowmappcf = 1;
484 else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa"))
485 r_shadow_shadowmappcf = 1;
487 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
491 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
492 switch (r_shadow_shadowmapfilterquality)
497 r_shadow_shadowmappcf = 1;
500 r_shadow_shadowmappcf = 1;
503 r_shadow_shadowmappcf = 2;
507 if (!r_fb.usedepthtextures)
508 r_shadow_shadowmapsampler = false;
509 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
511 case RENDERPATH_D3D9:
512 case RENDERPATH_D3D10:
513 case RENDERPATH_D3D11:
514 case RENDERPATH_SOFT:
515 r_shadow_shadowmapsampler = false;
516 r_shadow_shadowmappcf = 1;
517 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
519 case RENDERPATH_GL11:
520 case RENDERPATH_GL13:
521 case RENDERPATH_GLES1:
522 case RENDERPATH_GLES2:
527 if(R_CompileShader_CheckStaticParms())
531 qboolean R_Shadow_ShadowMappingEnabled(void)
533 switch (r_shadow_shadowmode)
535 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
542 static void R_Shadow_FreeShadowMaps(void)
544 Mod_AllocLightmap_Free(&r_shadow_shadowmapatlas_state);
546 R_Shadow_SetShadowMode();
548 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
552 if (r_shadow_shadowmap2ddepthtexture)
553 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
554 r_shadow_shadowmap2ddepthtexture = NULL;
556 if (r_shadow_shadowmap2ddepthbuffer)
557 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
558 r_shadow_shadowmap2ddepthbuffer = NULL;
560 if (r_shadow_shadowmapvsdcttexture)
561 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
562 r_shadow_shadowmapvsdcttexture = NULL;
565 static void r_shadow_start(void)
567 // allocate vertex processing arrays
568 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
569 r_shadow_attenuationgradienttexture = NULL;
570 r_shadow_attenuation2dtexture = NULL;
571 r_shadow_attenuation3dtexture = NULL;
572 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
573 r_shadow_shadowmap2ddepthtexture = NULL;
574 r_shadow_shadowmap2ddepthbuffer = NULL;
575 r_shadow_shadowmapvsdcttexture = NULL;
576 r_shadow_shadowmapmaxsize = 0;
577 r_shadow_shadowmaptexturesize = 0;
578 r_shadow_shadowmapfilterquality = -1;
579 r_shadow_shadowmapdepthbits = 0;
580 r_shadow_shadowmapvsdct = false;
581 r_shadow_shadowmapsampler = false;
582 r_shadow_shadowmappcf = 0;
585 R_Shadow_FreeShadowMaps();
587 r_shadow_texturepool = NULL;
588 r_shadow_filters_texturepool = NULL;
589 R_Shadow_ValidateCvars();
590 R_Shadow_MakeTextures();
591 r_shadow_scenemaxlights = 0;
592 r_shadow_scenenumlights = 0;
593 r_shadow_scenelightlist = NULL;
594 maxshadowtriangles = 0;
595 shadowelements = NULL;
596 maxshadowvertices = 0;
597 shadowvertex3f = NULL;
605 shadowmarklist = NULL;
610 shadowsideslist = NULL;
611 r_shadow_buffer_numleafpvsbytes = 0;
612 r_shadow_buffer_visitingleafpvs = NULL;
613 r_shadow_buffer_leafpvs = NULL;
614 r_shadow_buffer_leaflist = NULL;
615 r_shadow_buffer_numsurfacepvsbytes = 0;
616 r_shadow_buffer_surfacepvs = NULL;
617 r_shadow_buffer_surfacelist = NULL;
618 r_shadow_buffer_surfacesides = NULL;
619 r_shadow_buffer_numshadowtrispvsbytes = 0;
620 r_shadow_buffer_shadowtrispvs = NULL;
621 r_shadow_buffer_numlighttrispvsbytes = 0;
622 r_shadow_buffer_lighttrispvs = NULL;
624 r_shadow_usingdeferredprepass = false;
625 r_shadow_prepass_width = r_shadow_prepass_height = 0;
627 // determine renderpath specific capabilities, we don't need to figure
628 // these out per frame...
629 switch(vid.renderpath)
631 case RENDERPATH_GL20:
632 r_shadow_bouncegrid_state.allowdirectionalshading = true;
633 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
635 case RENDERPATH_GLES2:
636 // for performance reasons, do not use directional shading on GLES devices
637 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
639 // these renderpaths do not currently have the code to display the bouncegrid, so disable it on them...
640 case RENDERPATH_GL11:
641 case RENDERPATH_GL13:
642 case RENDERPATH_GLES1:
643 case RENDERPATH_SOFT:
644 case RENDERPATH_D3D9:
645 case RENDERPATH_D3D10:
646 case RENDERPATH_D3D11:
651 static void R_Shadow_FreeDeferred(void);
652 static void r_shadow_shutdown(void)
655 R_Shadow_UncompileWorldLights();
657 R_Shadow_FreeShadowMaps();
659 r_shadow_usingdeferredprepass = false;
660 if (r_shadow_prepass_width)
661 R_Shadow_FreeDeferred();
662 r_shadow_prepass_width = r_shadow_prepass_height = 0;
665 r_shadow_scenemaxlights = 0;
666 r_shadow_scenenumlights = 0;
667 if (r_shadow_scenelightlist)
668 Mem_Free(r_shadow_scenelightlist);
669 r_shadow_scenelightlist = NULL;
670 r_shadow_bouncegrid_state.highpixels = NULL;
671 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
672 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
673 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
674 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
675 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
676 r_shadow_bouncegrid_state.maxsplatpaths = 0;
677 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
678 r_shadow_attenuationgradienttexture = NULL;
679 r_shadow_attenuation2dtexture = NULL;
680 r_shadow_attenuation3dtexture = NULL;
681 R_FreeTexturePool(&r_shadow_texturepool);
682 R_FreeTexturePool(&r_shadow_filters_texturepool);
683 maxshadowtriangles = 0;
685 Mem_Free(shadowelements);
686 shadowelements = NULL;
688 Mem_Free(shadowvertex3f);
689 shadowvertex3f = NULL;
692 Mem_Free(vertexupdate);
695 Mem_Free(vertexremap);
701 Mem_Free(shadowmark);
704 Mem_Free(shadowmarklist);
705 shadowmarklist = NULL;
710 Mem_Free(shadowsides);
713 Mem_Free(shadowsideslist);
714 shadowsideslist = NULL;
715 r_shadow_buffer_numleafpvsbytes = 0;
716 if (r_shadow_buffer_visitingleafpvs)
717 Mem_Free(r_shadow_buffer_visitingleafpvs);
718 r_shadow_buffer_visitingleafpvs = NULL;
719 if (r_shadow_buffer_leafpvs)
720 Mem_Free(r_shadow_buffer_leafpvs);
721 r_shadow_buffer_leafpvs = NULL;
722 if (r_shadow_buffer_leaflist)
723 Mem_Free(r_shadow_buffer_leaflist);
724 r_shadow_buffer_leaflist = NULL;
725 r_shadow_buffer_numsurfacepvsbytes = 0;
726 if (r_shadow_buffer_surfacepvs)
727 Mem_Free(r_shadow_buffer_surfacepvs);
728 r_shadow_buffer_surfacepvs = NULL;
729 if (r_shadow_buffer_surfacelist)
730 Mem_Free(r_shadow_buffer_surfacelist);
731 r_shadow_buffer_surfacelist = NULL;
732 if (r_shadow_buffer_surfacesides)
733 Mem_Free(r_shadow_buffer_surfacesides);
734 r_shadow_buffer_surfacesides = NULL;
735 r_shadow_buffer_numshadowtrispvsbytes = 0;
736 if (r_shadow_buffer_shadowtrispvs)
737 Mem_Free(r_shadow_buffer_shadowtrispvs);
738 r_shadow_buffer_numlighttrispvsbytes = 0;
739 if (r_shadow_buffer_lighttrispvs)
740 Mem_Free(r_shadow_buffer_lighttrispvs);
743 static void r_shadow_newmap(void)
745 r_shadow_bouncegrid_state.highpixels = NULL;
746 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
747 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
748 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
749 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
750 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
751 r_shadow_bouncegrid_state.maxsplatpaths = 0;
752 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
753 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
754 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
755 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
756 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
757 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
758 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
759 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
760 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
761 R_Shadow_EditLights_Reload_f();
764 void R_Shadow_Init(void)
766 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
767 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
768 Cvar_RegisterVariable(&r_shadow_usebihculling);
769 Cvar_RegisterVariable(&r_shadow_usenormalmap);
770 Cvar_RegisterVariable(&r_shadow_debuglight);
771 Cvar_RegisterVariable(&r_shadow_deferred);
772 Cvar_RegisterVariable(&r_shadow_gloss);
773 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
774 Cvar_RegisterVariable(&r_shadow_glossintensity);
775 Cvar_RegisterVariable(&r_shadow_glossexponent);
776 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
777 Cvar_RegisterVariable(&r_shadow_glossexact);
778 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
779 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
780 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
781 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
782 Cvar_RegisterVariable(&r_shadow_projectdistance);
783 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
784 Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
785 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
786 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
787 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
788 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
789 Cvar_RegisterVariable(&r_shadow_realtime_world);
790 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
791 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
792 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
793 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
794 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
795 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
796 Cvar_RegisterVariable(&r_shadow_scissor);
797 Cvar_RegisterVariable(&r_shadow_shadowmapping);
798 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
799 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
800 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
801 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
802 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
803 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
804 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
805 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturesize);
806 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
807 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
808 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
809 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
810 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
811 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
812 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
813 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
814 Cvar_RegisterVariable(&r_shadow_polygonfactor);
815 Cvar_RegisterVariable(&r_shadow_polygonoffset);
816 Cvar_RegisterVariable(&r_shadow_texture3d);
817 Cvar_RegisterVariable(&r_shadow_culllights_pvs);
818 Cvar_RegisterVariable(&r_shadow_culllights_trace);
819 Cvar_RegisterVariable(&r_shadow_culllights_trace_eyejitter);
820 Cvar_RegisterVariable(&r_shadow_culllights_trace_enlarge);
821 Cvar_RegisterVariable(&r_shadow_culllights_trace_samples);
822 Cvar_RegisterVariable(&r_shadow_culllights_trace_tempsamples);
823 Cvar_RegisterVariable(&r_shadow_culllights_trace_delay);
824 Cvar_RegisterVariable(&r_shadow_bouncegrid);
825 Cvar_RegisterVariable(&r_shadow_bouncegrid_blur);
826 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
827 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_bounceminimumintensity);
828 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_culllightpaths);
829 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_directionalshading);
830 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_dlightparticlemultiplier);
831 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_hitmodels);
832 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_lightradiusscale);
833 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxbounce);
834 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxphotons);
835 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_quality);
836 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_spacing);
837 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_updateinterval);
838 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_x);
839 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_y);
840 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_z);
841 Cvar_RegisterVariable(&r_shadow_bouncegrid_floatcolors);
842 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
843 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
844 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize_conespread);
845 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize_initial);
846 Cvar_RegisterVariable(&r_shadow_bouncegrid_normalizevectors);
847 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
848 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
849 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_seed);
850 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_type);
851 Cvar_RegisterVariable(&r_shadow_bouncegrid_sortlightpaths);
852 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
853 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_bounceminimumintensity);
854 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
855 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
856 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
857 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxphotons);
858 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_quality);
859 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_spacing);
860 Cvar_RegisterVariable(&r_coronas);
861 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
862 Cvar_RegisterVariable(&r_coronas_occlusionquery);
863 Cvar_RegisterVariable(&gl_flashblend);
864 Cvar_RegisterVariable(&gl_ext_separatestencil);
865 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
866 R_Shadow_EditLights_Init();
867 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
868 r_shadow_scenemaxlights = 0;
869 r_shadow_scenenumlights = 0;
870 r_shadow_scenelightlist = NULL;
871 maxshadowtriangles = 0;
872 shadowelements = NULL;
873 maxshadowvertices = 0;
874 shadowvertex3f = NULL;
882 shadowmarklist = NULL;
887 shadowsideslist = NULL;
888 r_shadow_buffer_numleafpvsbytes = 0;
889 r_shadow_buffer_visitingleafpvs = NULL;
890 r_shadow_buffer_leafpvs = NULL;
891 r_shadow_buffer_leaflist = NULL;
892 r_shadow_buffer_numsurfacepvsbytes = 0;
893 r_shadow_buffer_surfacepvs = NULL;
894 r_shadow_buffer_surfacelist = NULL;
895 r_shadow_buffer_surfacesides = NULL;
896 r_shadow_buffer_shadowtrispvs = NULL;
897 r_shadow_buffer_lighttrispvs = NULL;
898 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
901 matrix4x4_t matrix_attenuationxyz =
904 {0.5, 0.0, 0.0, 0.5},
905 {0.0, 0.5, 0.0, 0.5},
906 {0.0, 0.0, 0.5, 0.5},
911 matrix4x4_t matrix_attenuationz =
914 {0.0, 0.0, 0.5, 0.5},
915 {0.0, 0.0, 0.0, 0.5},
916 {0.0, 0.0, 0.0, 0.5},
921 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
923 numvertices = ((numvertices + 255) & ~255) * vertscale;
924 numtriangles = ((numtriangles + 255) & ~255) * triscale;
925 // make sure shadowelements is big enough for this volume
926 if (maxshadowtriangles < numtriangles)
928 maxshadowtriangles = numtriangles;
930 Mem_Free(shadowelements);
931 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
933 // make sure shadowvertex3f is big enough for this volume
934 if (maxshadowvertices < numvertices)
936 maxshadowvertices = numvertices;
938 Mem_Free(shadowvertex3f);
939 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
943 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
945 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
946 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
947 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
948 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
949 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
951 if (r_shadow_buffer_visitingleafpvs)
952 Mem_Free(r_shadow_buffer_visitingleafpvs);
953 if (r_shadow_buffer_leafpvs)
954 Mem_Free(r_shadow_buffer_leafpvs);
955 if (r_shadow_buffer_leaflist)
956 Mem_Free(r_shadow_buffer_leaflist);
957 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
958 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
959 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
960 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
962 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
964 if (r_shadow_buffer_surfacepvs)
965 Mem_Free(r_shadow_buffer_surfacepvs);
966 if (r_shadow_buffer_surfacelist)
967 Mem_Free(r_shadow_buffer_surfacelist);
968 if (r_shadow_buffer_surfacesides)
969 Mem_Free(r_shadow_buffer_surfacesides);
970 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
971 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
972 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
973 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
975 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
977 if (r_shadow_buffer_shadowtrispvs)
978 Mem_Free(r_shadow_buffer_shadowtrispvs);
979 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
980 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
982 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
984 if (r_shadow_buffer_lighttrispvs)
985 Mem_Free(r_shadow_buffer_lighttrispvs);
986 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
987 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
991 void R_Shadow_PrepareShadowMark(int numtris)
993 // make sure shadowmark is big enough for this volume
994 if (maxshadowmark < numtris)
996 maxshadowmark = numtris;
998 Mem_Free(shadowmark);
1000 Mem_Free(shadowmarklist);
1001 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
1002 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
1003 shadowmarkcount = 0;
1006 // if shadowmarkcount wrapped we clear the array and adjust accordingly
1007 if (shadowmarkcount == 0)
1009 shadowmarkcount = 1;
1010 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
1015 void R_Shadow_PrepareShadowSides(int numtris)
1017 if (maxshadowsides < numtris)
1019 maxshadowsides = numtris;
1021 Mem_Free(shadowsides);
1022 if (shadowsideslist)
1023 Mem_Free(shadowsideslist);
1024 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
1025 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
1030 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)
1033 int outtriangles = 0, outvertices = 0;
1035 const float *vertex;
1036 float ratio, direction[3], projectvector[3];
1038 if (projectdirection)
1039 VectorScale(projectdirection, projectdistance, projectvector);
1041 VectorClear(projectvector);
1043 // create the vertices
1044 if (projectdirection)
1046 for (i = 0;i < numshadowmarktris;i++)
1048 element = inelement3i + shadowmarktris[i] * 3;
1049 for (j = 0;j < 3;j++)
1051 if (vertexupdate[element[j]] != vertexupdatenum)
1053 vertexupdate[element[j]] = vertexupdatenum;
1054 vertexremap[element[j]] = outvertices;
1055 vertex = invertex3f + element[j] * 3;
1056 // project one copy of the vertex according to projectvector
1057 VectorCopy(vertex, outvertex3f);
1058 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1067 for (i = 0;i < numshadowmarktris;i++)
1069 element = inelement3i + shadowmarktris[i] * 3;
1070 for (j = 0;j < 3;j++)
1072 if (vertexupdate[element[j]] != vertexupdatenum)
1074 vertexupdate[element[j]] = vertexupdatenum;
1075 vertexremap[element[j]] = outvertices;
1076 vertex = invertex3f + element[j] * 3;
1077 // project one copy of the vertex to the sphere radius of the light
1078 // (FIXME: would projecting it to the light box be better?)
1079 VectorSubtract(vertex, projectorigin, direction);
1080 ratio = projectdistance / VectorLength(direction);
1081 VectorCopy(vertex, outvertex3f);
1082 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1090 if (r_shadow_frontsidecasting.integer)
1092 for (i = 0;i < numshadowmarktris;i++)
1094 int remappedelement[3];
1096 const int *neighbortriangle;
1098 markindex = shadowmarktris[i] * 3;
1099 element = inelement3i + markindex;
1100 neighbortriangle = inneighbor3i + markindex;
1101 // output the front and back triangles
1102 outelement3i[0] = vertexremap[element[0]];
1103 outelement3i[1] = vertexremap[element[1]];
1104 outelement3i[2] = vertexremap[element[2]];
1105 outelement3i[3] = vertexremap[element[2]] + 1;
1106 outelement3i[4] = vertexremap[element[1]] + 1;
1107 outelement3i[5] = vertexremap[element[0]] + 1;
1111 // output the sides (facing outward from this triangle)
1112 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1114 remappedelement[0] = vertexremap[element[0]];
1115 remappedelement[1] = vertexremap[element[1]];
1116 outelement3i[0] = remappedelement[1];
1117 outelement3i[1] = remappedelement[0];
1118 outelement3i[2] = remappedelement[0] + 1;
1119 outelement3i[3] = remappedelement[1];
1120 outelement3i[4] = remappedelement[0] + 1;
1121 outelement3i[5] = remappedelement[1] + 1;
1126 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1128 remappedelement[1] = vertexremap[element[1]];
1129 remappedelement[2] = vertexremap[element[2]];
1130 outelement3i[0] = remappedelement[2];
1131 outelement3i[1] = remappedelement[1];
1132 outelement3i[2] = remappedelement[1] + 1;
1133 outelement3i[3] = remappedelement[2];
1134 outelement3i[4] = remappedelement[1] + 1;
1135 outelement3i[5] = remappedelement[2] + 1;
1140 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1142 remappedelement[0] = vertexremap[element[0]];
1143 remappedelement[2] = vertexremap[element[2]];
1144 outelement3i[0] = remappedelement[0];
1145 outelement3i[1] = remappedelement[2];
1146 outelement3i[2] = remappedelement[2] + 1;
1147 outelement3i[3] = remappedelement[0];
1148 outelement3i[4] = remappedelement[2] + 1;
1149 outelement3i[5] = remappedelement[0] + 1;
1158 for (i = 0;i < numshadowmarktris;i++)
1160 int remappedelement[3];
1162 const int *neighbortriangle;
1164 markindex = shadowmarktris[i] * 3;
1165 element = inelement3i + markindex;
1166 neighbortriangle = inneighbor3i + markindex;
1167 // output the front and back triangles
1168 outelement3i[0] = vertexremap[element[2]];
1169 outelement3i[1] = vertexremap[element[1]];
1170 outelement3i[2] = vertexremap[element[0]];
1171 outelement3i[3] = vertexremap[element[0]] + 1;
1172 outelement3i[4] = vertexremap[element[1]] + 1;
1173 outelement3i[5] = vertexremap[element[2]] + 1;
1177 // output the sides (facing outward from this triangle)
1178 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1180 remappedelement[0] = vertexremap[element[0]];
1181 remappedelement[1] = vertexremap[element[1]];
1182 outelement3i[0] = remappedelement[0];
1183 outelement3i[1] = remappedelement[1];
1184 outelement3i[2] = remappedelement[1] + 1;
1185 outelement3i[3] = remappedelement[0];
1186 outelement3i[4] = remappedelement[1] + 1;
1187 outelement3i[5] = remappedelement[0] + 1;
1192 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1194 remappedelement[1] = vertexremap[element[1]];
1195 remappedelement[2] = vertexremap[element[2]];
1196 outelement3i[0] = remappedelement[1];
1197 outelement3i[1] = remappedelement[2];
1198 outelement3i[2] = remappedelement[2] + 1;
1199 outelement3i[3] = remappedelement[1];
1200 outelement3i[4] = remappedelement[2] + 1;
1201 outelement3i[5] = remappedelement[1] + 1;
1206 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1208 remappedelement[0] = vertexremap[element[0]];
1209 remappedelement[2] = vertexremap[element[2]];
1210 outelement3i[0] = remappedelement[2];
1211 outelement3i[1] = remappedelement[0];
1212 outelement3i[2] = remappedelement[0] + 1;
1213 outelement3i[3] = remappedelement[2];
1214 outelement3i[4] = remappedelement[0] + 1;
1215 outelement3i[5] = remappedelement[2] + 1;
1223 *outnumvertices = outvertices;
1224 return outtriangles;
1227 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)
1230 int outtriangles = 0, outvertices = 0;
1232 const float *vertex;
1233 float ratio, direction[3], projectvector[3];
1236 if (projectdirection)
1237 VectorScale(projectdirection, projectdistance, projectvector);
1239 VectorClear(projectvector);
1241 for (i = 0;i < numshadowmarktris;i++)
1243 int remappedelement[3];
1245 const int *neighbortriangle;
1247 markindex = shadowmarktris[i] * 3;
1248 neighbortriangle = inneighbor3i + markindex;
1249 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1250 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1251 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1252 if (side[0] + side[1] + side[2] == 0)
1256 element = inelement3i + markindex;
1258 // create the vertices
1259 for (j = 0;j < 3;j++)
1261 if (side[j] + side[j+1] == 0)
1264 if (vertexupdate[k] != vertexupdatenum)
1266 vertexupdate[k] = vertexupdatenum;
1267 vertexremap[k] = outvertices;
1268 vertex = invertex3f + k * 3;
1269 VectorCopy(vertex, outvertex3f);
1270 if (projectdirection)
1272 // project one copy of the vertex according to projectvector
1273 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1277 // project one copy of the vertex to the sphere radius of the light
1278 // (FIXME: would projecting it to the light box be better?)
1279 VectorSubtract(vertex, projectorigin, direction);
1280 ratio = projectdistance / VectorLength(direction);
1281 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1288 // output the sides (facing outward from this triangle)
1291 remappedelement[0] = vertexremap[element[0]];
1292 remappedelement[1] = vertexremap[element[1]];
1293 outelement3i[0] = remappedelement[1];
1294 outelement3i[1] = remappedelement[0];
1295 outelement3i[2] = remappedelement[0] + 1;
1296 outelement3i[3] = remappedelement[1];
1297 outelement3i[4] = remappedelement[0] + 1;
1298 outelement3i[5] = remappedelement[1] + 1;
1305 remappedelement[1] = vertexremap[element[1]];
1306 remappedelement[2] = vertexremap[element[2]];
1307 outelement3i[0] = remappedelement[2];
1308 outelement3i[1] = remappedelement[1];
1309 outelement3i[2] = remappedelement[1] + 1;
1310 outelement3i[3] = remappedelement[2];
1311 outelement3i[4] = remappedelement[1] + 1;
1312 outelement3i[5] = remappedelement[2] + 1;
1319 remappedelement[0] = vertexremap[element[0]];
1320 remappedelement[2] = vertexremap[element[2]];
1321 outelement3i[0] = remappedelement[0];
1322 outelement3i[1] = remappedelement[2];
1323 outelement3i[2] = remappedelement[2] + 1;
1324 outelement3i[3] = remappedelement[0];
1325 outelement3i[4] = remappedelement[2] + 1;
1326 outelement3i[5] = remappedelement[0] + 1;
1333 *outnumvertices = outvertices;
1334 return outtriangles;
1337 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)
1343 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1345 tend = firsttriangle + numtris;
1346 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1348 // surface box entirely inside light box, no box cull
1349 if (projectdirection)
1351 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1353 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1354 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1355 shadowmarklist[numshadowmark++] = t;
1360 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1361 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1362 shadowmarklist[numshadowmark++] = t;
1367 // surface box not entirely inside light box, cull each triangle
1368 if (projectdirection)
1370 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1372 v[0] = invertex3f + e[0] * 3;
1373 v[1] = invertex3f + e[1] * 3;
1374 v[2] = invertex3f + e[2] * 3;
1375 TriangleNormal(v[0], v[1], v[2], normal);
1376 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1377 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1378 shadowmarklist[numshadowmark++] = t;
1383 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1385 v[0] = invertex3f + e[0] * 3;
1386 v[1] = invertex3f + e[1] * 3;
1387 v[2] = invertex3f + e[2] * 3;
1388 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1389 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1390 shadowmarklist[numshadowmark++] = t;
1396 static qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1401 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1403 // check if the shadow volume intersects the near plane
1405 // a ray between the eye and light origin may intersect the caster,
1406 // indicating that the shadow may touch the eye location, however we must
1407 // test the near plane (a polygon), not merely the eye location, so it is
1408 // easiest to enlarge the caster bounding shape slightly for this.
1414 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)
1416 int i, tris, outverts;
1417 if (projectdistance < 0.1)
1419 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1422 if (!numverts || !nummarktris)
1424 // make sure shadowelements is big enough for this volume
1425 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1426 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1428 if (maxvertexupdate < numverts)
1430 maxvertexupdate = numverts;
1432 Mem_Free(vertexupdate);
1434 Mem_Free(vertexremap);
1435 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1436 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1437 vertexupdatenum = 0;
1440 if (vertexupdatenum == 0)
1442 vertexupdatenum = 1;
1443 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1444 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1447 for (i = 0;i < nummarktris;i++)
1448 shadowmark[marktris[i]] = shadowmarkcount;
1450 if (r_shadow_compilingrtlight)
1452 // if we're compiling an rtlight, capture the mesh
1453 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1454 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1455 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1456 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1458 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1460 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1461 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1462 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1466 // decide which type of shadow to generate and set stencil mode
1467 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1468 // generate the sides or a solid volume, depending on type
1469 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1470 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1472 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1473 r_refdef.stats[r_stat_lights_dynamicshadowtriangles] += tris;
1474 r_refdef.stats[r_stat_lights_shadowtriangles] += tris;
1475 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1477 // increment stencil if frontface is infront of depthbuffer
1478 GL_CullFace(r_refdef.view.cullface_front);
1479 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1480 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1481 // decrement stencil if backface is infront of depthbuffer
1482 GL_CullFace(r_refdef.view.cullface_back);
1483 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1485 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1487 // decrement stencil if backface is behind depthbuffer
1488 GL_CullFace(r_refdef.view.cullface_front);
1489 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1490 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1491 // increment stencil if frontface is behind depthbuffer
1492 GL_CullFace(r_refdef.view.cullface_back);
1493 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1495 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1496 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1500 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1502 // p1, p2, p3 are in the cubemap's local coordinate system
1503 // bias = border/(size - border)
1506 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1507 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1508 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1509 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1511 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1512 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1513 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1514 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1516 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1517 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1518 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1520 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1521 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1522 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1523 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1525 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1526 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1527 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1528 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1530 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1531 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1532 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1534 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1535 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1536 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1537 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1539 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1540 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1541 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1542 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1544 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1545 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1546 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1551 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1553 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1554 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1557 VectorSubtract(maxs, mins, radius);
1558 VectorScale(radius, 0.5f, radius);
1559 VectorAdd(mins, radius, center);
1560 Matrix4x4_Transform(worldtolight, center, lightcenter);
1561 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1562 VectorSubtract(lightcenter, lightradius, pmin);
1563 VectorAdd(lightcenter, lightradius, pmax);
1565 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1566 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1567 if(ap1 > bias*an1 && ap2 > bias*an2)
1569 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1570 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1571 if(an1 > bias*ap1 && an2 > bias*ap2)
1573 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1574 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1576 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1577 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1578 if(ap1 > bias*an1 && ap2 > bias*an2)
1580 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1581 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1582 if(an1 > bias*ap1 && an2 > bias*ap2)
1584 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1585 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1587 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1588 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1589 if(ap1 > bias*an1 && ap2 > bias*an2)
1591 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1592 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1593 if(an1 > bias*ap1 && an2 > bias*ap2)
1595 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1596 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1601 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1603 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1605 // p is in the cubemap's local coordinate system
1606 // bias = border/(size - border)
1607 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1608 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1609 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1611 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1612 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1613 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1614 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1615 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1616 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1620 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1624 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1625 float scale = (size - 2*border)/size, len;
1626 float bias = border / (float)(size - border), dp, dn, ap, an;
1627 // check if cone enclosing side would cross frustum plane
1628 scale = 2 / (scale*scale + 2);
1629 Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
1630 for (i = 0;i < 5;i++)
1632 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
1634 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1635 len = scale*VectorLength2(n);
1636 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1637 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1638 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1640 if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1642 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1643 len = scale*VectorLength2(n);
1644 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1645 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1646 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1648 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1649 // check if frustum corners/origin cross plane sides
1651 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1652 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1653 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1654 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1655 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1656 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1657 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1658 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1659 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1660 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1661 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1662 for (i = 0;i < 4;i++)
1664 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1665 VectorSubtract(n, p, n);
1666 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1667 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1668 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1669 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1670 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1671 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1672 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1673 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1674 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1677 // finite version, assumes corners are a finite distance from origin dependent on far plane
1678 for (i = 0;i < 5;i++)
1680 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1681 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1682 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1683 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1684 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1685 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1686 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1687 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1688 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1689 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1692 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1695 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)
1703 int mask, surfacemask = 0;
1704 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1706 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1707 tend = firsttriangle + numtris;
1708 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1710 // surface box entirely inside light box, no box cull
1711 if (projectdirection)
1713 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1715 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1716 TriangleNormal(v[0], v[1], v[2], normal);
1717 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1719 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1720 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1721 surfacemask |= mask;
1724 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;
1725 shadowsides[numshadowsides] = mask;
1726 shadowsideslist[numshadowsides++] = t;
1733 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1735 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1736 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1738 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1739 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1740 surfacemask |= mask;
1743 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;
1744 shadowsides[numshadowsides] = mask;
1745 shadowsideslist[numshadowsides++] = t;
1753 // surface box not entirely inside light box, cull each triangle
1754 if (projectdirection)
1756 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1758 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1759 TriangleNormal(v[0], v[1], v[2], normal);
1760 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1761 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1763 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1764 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1765 surfacemask |= mask;
1768 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;
1769 shadowsides[numshadowsides] = mask;
1770 shadowsideslist[numshadowsides++] = t;
1777 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1779 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1780 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1781 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1783 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1784 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1785 surfacemask |= mask;
1788 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;
1789 shadowsides[numshadowsides] = mask;
1790 shadowsideslist[numshadowsides++] = t;
1799 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)
1801 int i, j, outtriangles = 0;
1802 int *outelement3i[6];
1803 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1805 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1806 // make sure shadowelements is big enough for this mesh
1807 if (maxshadowtriangles < outtriangles)
1808 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1810 // compute the offset and size of the separate index lists for each cubemap side
1812 for (i = 0;i < 6;i++)
1814 outelement3i[i] = shadowelements + outtriangles * 3;
1815 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1816 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1817 outtriangles += sidetotals[i];
1820 // gather up the (sparse) triangles into separate index lists for each cubemap side
1821 for (i = 0;i < numsidetris;i++)
1823 const int *element = elements + sidetris[i] * 3;
1824 for (j = 0;j < 6;j++)
1826 if (sides[i] & (1 << j))
1828 outelement3i[j][0] = element[0];
1829 outelement3i[j][1] = element[1];
1830 outelement3i[j][2] = element[2];
1831 outelement3i[j] += 3;
1836 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1839 static void R_Shadow_MakeTextures_MakeCorona(void)
1843 unsigned char pixels[32][32][4];
1844 for (y = 0;y < 32;y++)
1846 dy = (y - 15.5f) * (1.0f / 16.0f);
1847 for (x = 0;x < 32;x++)
1849 dx = (x - 15.5f) * (1.0f / 16.0f);
1850 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1851 a = bound(0, a, 255);
1852 pixels[y][x][0] = a;
1853 pixels[y][x][1] = a;
1854 pixels[y][x][2] = a;
1855 pixels[y][x][3] = 255;
1858 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, false);
1861 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1863 float dist = sqrt(x*x+y*y+z*z);
1864 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1865 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1866 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1869 static void R_Shadow_MakeTextures(void)
1872 float intensity, dist;
1874 R_Shadow_FreeShadowMaps();
1875 R_FreeTexturePool(&r_shadow_texturepool);
1876 r_shadow_texturepool = R_AllocTexturePool();
1877 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1878 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1879 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1880 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1881 for (x = 0;x <= ATTENTABLESIZE;x++)
1883 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1884 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1885 r_shadow_attentable[x] = bound(0, intensity, 1);
1887 // 1D gradient texture
1888 for (x = 0;x < ATTEN1DSIZE;x++)
1889 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1890 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1891 // 2D circle texture
1892 for (y = 0;y < ATTEN2DSIZE;y++)
1893 for (x = 0;x < ATTEN2DSIZE;x++)
1894 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);
1895 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1896 // 3D sphere texture
1897 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1899 for (z = 0;z < ATTEN3DSIZE;z++)
1900 for (y = 0;y < ATTEN3DSIZE;y++)
1901 for (x = 0;x < ATTEN3DSIZE;x++)
1902 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));
1903 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);
1906 r_shadow_attenuation3dtexture = NULL;
1909 R_Shadow_MakeTextures_MakeCorona();
1911 // Editor light sprites
1912 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1929 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1930 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1947 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1948 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1965 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1966 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1983 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1984 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
2001 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
2002 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
2019 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
2022 void R_Shadow_ValidateCvars(void)
2024 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
2025 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
2026 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
2027 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
2028 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
2029 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
2032 void R_Shadow_RenderMode_Begin(void)
2038 R_Shadow_ValidateCvars();
2040 if (!r_shadow_attenuation2dtexture
2041 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
2042 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
2043 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
2044 R_Shadow_MakeTextures();
2047 R_Mesh_ResetTextureState();
2048 GL_BlendFunc(GL_ONE, GL_ZERO);
2049 GL_DepthRange(0, 1);
2050 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
2052 GL_DepthMask(false);
2053 GL_Color(0, 0, 0, 1);
2054 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2056 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2058 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
2060 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
2061 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
2063 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
2065 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
2066 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
2070 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
2071 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
2074 switch(vid.renderpath)
2076 case RENDERPATH_GL20:
2077 case RENDERPATH_D3D9:
2078 case RENDERPATH_D3D10:
2079 case RENDERPATH_D3D11:
2080 case RENDERPATH_SOFT:
2081 case RENDERPATH_GLES2:
2082 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
2084 case RENDERPATH_GL11:
2085 case RENDERPATH_GL13:
2086 case RENDERPATH_GLES1:
2087 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
2088 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
2089 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
2090 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
2091 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
2092 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
2094 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
2100 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
2101 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
2102 r_shadow_drawbuffer = drawbuffer;
2103 r_shadow_readbuffer = readbuffer;
2105 r_shadow_cullface_front = r_refdef.view.cullface_front;
2106 r_shadow_cullface_back = r_refdef.view.cullface_back;
2109 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
2111 rsurface.rtlight = rtlight;
2114 void R_Shadow_RenderMode_Reset(void)
2116 R_Mesh_ResetTextureState();
2117 R_Mesh_SetRenderTargets(r_shadow_viewfbo, r_shadow_viewdepthtexture, r_shadow_viewcolortexture, NULL, NULL, NULL);
2118 R_SetViewport(&r_refdef.view.viewport);
2119 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
2120 GL_DepthRange(0, 1);
2122 GL_DepthMask(false);
2123 GL_DepthFunc(GL_LEQUAL);
2124 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2125 r_refdef.view.cullface_front = r_shadow_cullface_front;
2126 r_refdef.view.cullface_back = r_shadow_cullface_back;
2127 GL_CullFace(r_refdef.view.cullface_back);
2128 GL_Color(1, 1, 1, 1);
2129 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2130 GL_BlendFunc(GL_ONE, GL_ZERO);
2131 R_SetupShader_Generic_NoTexture(false, false);
2132 r_shadow_usingshadowmap2d = false;
2133 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2136 void R_Shadow_ClearStencil(void)
2138 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2139 r_refdef.stats[r_stat_lights_clears]++;
2142 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2144 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2145 if (r_shadow_rendermode == mode)
2147 R_Shadow_RenderMode_Reset();
2148 GL_DepthFunc(GL_LESS);
2149 GL_ColorMask(0, 0, 0, 0);
2150 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2151 GL_CullFace(GL_NONE);
2152 R_SetupShader_DepthOrShadow(false, false, false); // FIXME test if we have a skeletal model?
2153 r_shadow_rendermode = mode;
2158 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2159 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2160 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2162 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2163 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2164 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2169 static void R_Shadow_MakeVSDCT(void)
2171 // maps to a 2x3 texture rectangle with normalized coordinates
2176 // stores abs(dir.xy), offset.xy/2.5
2177 unsigned char data[4*6] =
2179 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2180 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2181 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2182 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2183 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2184 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2186 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2189 static void R_Shadow_MakeShadowMap(int texturesize)
2191 switch (r_shadow_shadowmode)
2193 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2194 if (r_shadow_shadowmap2ddepthtexture) return;
2195 if (r_fb.usedepthtextures)
2197 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);
2198 r_shadow_shadowmap2ddepthbuffer = NULL;
2199 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2203 r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", texturesize, texturesize, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2204 r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
2205 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2213 void R_Shadow_ClearShadowMapTexture(void)
2215 r_viewport_t viewport;
2216 float clearcolor[4];
2218 // if they don't exist, create our textures now
2219 if (!r_shadow_shadowmap2ddepthtexture)
2220 R_Shadow_MakeShadowMap(r_shadow_shadowmaptexturesize);
2221 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2222 R_Shadow_MakeVSDCT();
2224 // we're setting up to render shadowmaps, so change rendermode
2225 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2227 R_Mesh_ResetTextureState();
2228 R_Shadow_RenderMode_Reset();
2229 if (r_shadow_shadowmap2ddepthbuffer)
2230 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2232 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2233 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2234 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2238 // we have to set a viewport to clear anything in some renderpaths (D3D)
2239 R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize, 0, 0, 1.0, 1.0, 0.001f, 1.0f, NULL);
2240 R_SetViewport(&viewport);
2241 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2242 if (r_shadow_shadowmap2ddepthbuffer)
2243 GL_ColorMask(1, 1, 1, 1);
2245 GL_ColorMask(0, 0, 0, 0);
2246 switch (vid.renderpath)
2248 case RENDERPATH_GL11:
2249 case RENDERPATH_GL13:
2250 case RENDERPATH_GL20:
2251 case RENDERPATH_SOFT:
2252 case RENDERPATH_GLES1:
2253 case RENDERPATH_GLES2:
2254 GL_CullFace(r_refdef.view.cullface_back);
2256 case RENDERPATH_D3D9:
2257 case RENDERPATH_D3D10:
2258 case RENDERPATH_D3D11:
2259 // we invert the cull mode because we flip the projection matrix
2260 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2261 GL_CullFace(r_refdef.view.cullface_front);
2264 Vector4Set(clearcolor, 1, 1, 1, 1);
2265 if (r_shadow_shadowmap2ddepthbuffer)
2266 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2268 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2271 static void R_Shadow_SetShadowmapParametersForLight(qboolean noselfshadowpass)
2273 int size = rsurface.rtlight->shadowmapatlassidesize;
2274 float nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2275 float farclip = 1.0f;
2276 float bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2277 r_shadow_lightshadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
2278 r_shadow_lightshadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
2279 r_shadow_lightshadowmap_texturescale[2] = rsurface.rtlight->shadowmapatlasposition[0] + (noselfshadowpass ? size * 2 : 0);
2280 r_shadow_lightshadowmap_texturescale[3] = rsurface.rtlight->shadowmapatlasposition[1];
2281 r_shadow_lightshadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2282 r_shadow_lightshadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2283 r_shadow_lightshadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2284 r_shadow_lightshadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2285 if (r_shadow_shadowmap2ddepthbuffer)
2287 // completely different meaning than in depthtexture approach
2288 r_shadow_lightshadowmap_parameters[1] = 0;
2289 r_shadow_lightshadowmap_parameters[3] = -bias;
2293 static void R_Shadow_RenderMode_ShadowMap(int side, int size, int x, int y)
2295 float nearclip, farclip, bias;
2296 r_viewport_t viewport;
2298 float clearcolor[4];
2300 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_SHADOWMAP2D)
2302 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2304 R_Mesh_ResetTextureState();
2305 R_Shadow_RenderMode_Reset();
2306 if (r_shadow_shadowmap2ddepthbuffer)
2307 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2309 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2310 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2311 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2316 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2318 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2320 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
2321 R_SetViewport(&viewport);
2322 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2323 flipped = (side & 1) ^ (side >> 2);
2324 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2325 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2327 Vector4Set(clearcolor, 1,1,1,1);
2328 if (r_shadow_shadowmap2ddepthbuffer)
2329 GL_ColorMask(1,1,1,1);
2331 GL_ColorMask(0,0,0,0);
2332 switch(vid.renderpath)
2334 case RENDERPATH_GL11:
2335 case RENDERPATH_GL13:
2336 case RENDERPATH_GL20:
2337 case RENDERPATH_SOFT:
2338 case RENDERPATH_GLES1:
2339 case RENDERPATH_GLES2:
2340 GL_CullFace(r_refdef.view.cullface_back);
2342 case RENDERPATH_D3D9:
2343 case RENDERPATH_D3D10:
2344 case RENDERPATH_D3D11:
2345 // we invert the cull mode because we flip the projection matrix
2346 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2347 GL_CullFace(r_refdef.view.cullface_front);
2351 // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
2352 r_shadow_shadowmapside = side;
2355 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass)
2357 R_Mesh_ResetTextureState();
2360 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2361 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2362 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2363 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2366 R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
2367 R_Shadow_RenderMode_Reset();
2368 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2370 GL_DepthFunc(GL_EQUAL);
2371 // do global setup needed for the chosen lighting mode
2372 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2373 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2374 r_shadow_usingshadowmap2d = shadowmapping;
2375 r_shadow_rendermode = r_shadow_lightingrendermode;
2376 // only draw light where this geometry was already rendered AND the
2377 // stencil is 128 (values other than this mean shadow)
2379 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2381 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2384 static const unsigned short bboxelements[36] =
2394 static const float bboxpoints[8][3] =
2406 void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping)
2409 float vertex3f[8*3];
2410 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2411 // do global setup needed for the chosen lighting mode
2412 R_Shadow_RenderMode_Reset();
2413 r_shadow_rendermode = r_shadow_lightingrendermode;
2414 R_EntityMatrix(&identitymatrix);
2415 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2416 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2417 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
2418 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2420 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
2422 r_shadow_usingshadowmap2d = shadowmapping;
2424 // render the lighting
2425 R_SetupShader_DeferredLight(rsurface.rtlight);
2426 for (i = 0;i < 8;i++)
2427 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2428 GL_ColorMask(1,1,1,1);
2429 GL_DepthMask(false);
2430 GL_DepthRange(0, 1);
2431 GL_PolygonOffset(0, 0);
2433 GL_DepthFunc(GL_GREATER);
2434 GL_CullFace(r_refdef.view.cullface_back);
2435 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
2436 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2439 #define MAXBOUNCEGRIDSPLATSIZE 7
2440 #define MAXBOUNCEGRIDSPLATSIZE1 (MAXBOUNCEGRIDSPLATSIZE+1)
2442 // these are temporary data per-frame, sorted and performed in a more
2443 // cache-friendly order than the original photons
2444 typedef struct r_shadow_bouncegrid_splatpath_s
2450 vec_t splatintensity;
2451 vec_t splatsize_current;
2452 vec_t splatsize_perstep;
2453 int remainingsplats;
2455 r_shadow_bouncegrid_splatpath_t;
2457 static void R_Shadow_BounceGrid_AddSplatPath(vec3_t originalstart, vec3_t originalend, vec3_t color, vec_t distancetraveled)
2467 r_shadow_bouncegrid_splatpath_t *path;
2469 // cull paths that fail R_CullBox in dynamic mode
2470 if (!r_shadow_bouncegrid_state.settings.staticmode
2471 && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
2473 vec3_t cullmins, cullmaxs;
2474 cullmins[0] = min(originalstart[0], originalend[0]) - r_shadow_bouncegrid_state.settings.spacing[0];
2475 cullmins[1] = min(originalstart[1], originalend[1]) - r_shadow_bouncegrid_state.settings.spacing[1];
2476 cullmins[2] = min(originalstart[2], originalend[2]) - r_shadow_bouncegrid_state.settings.spacing[2];
2477 cullmaxs[0] = max(originalstart[0], originalend[0]) + r_shadow_bouncegrid_state.settings.spacing[0];
2478 cullmaxs[1] = max(originalstart[1], originalend[1]) + r_shadow_bouncegrid_state.settings.spacing[1];
2479 cullmaxs[2] = max(originalstart[2], originalend[2]) + r_shadow_bouncegrid_state.settings.spacing[2];
2480 if (R_CullBox(cullmins, cullmaxs))
2484 // if the light path is going upward, reverse it - we always draw down.
2485 if (originalend[2] < originalstart[2])
2487 VectorCopy(originalend, start);
2488 VectorCopy(originalstart, end);
2492 VectorCopy(originalstart, start);
2493 VectorCopy(originalend, end);
2496 // transform to texture pixels
2497 start[0] = (start[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2498 start[1] = (start[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2499 start[2] = (start[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2500 end[0] = (end[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2501 end[1] = (end[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2502 end[2] = (end[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2504 // check if we need to grow the splatpaths array
2505 if (r_shadow_bouncegrid_state.maxsplatpaths <= r_shadow_bouncegrid_state.numsplatpaths)
2507 // double the limit, this will persist from frame to frame so we don't
2508 // make the same mistake each time
2509 r_shadow_bouncegrid_state.maxsplatpaths *= 2;
2510 if (r_shadow_bouncegrid_state.maxsplatpaths < 16384)
2511 r_shadow_bouncegrid_state.maxsplatpaths = 16384;
2512 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);
2515 // divide a series of splats along the length using the maximum axis
2516 VectorSubtract(end, start, diff);
2517 // pick the best axis to trace along
2519 if (diff[1]*diff[1] > diff[bestaxis]*diff[bestaxis])
2521 if (diff[2]*diff[2] > diff[bestaxis]*diff[bestaxis])
2523 len = fabs(diff[bestaxis]);
2525 numsplats = (int)(floor(len + 0.5f));
2527 numsplats = bound(0, numsplats, 1024);
2529 VectorSubtract(originalstart, originalend, originaldir);
2530 VectorNormalize(originaldir);
2532 path = r_shadow_bouncegrid_state.splatpaths + r_shadow_bouncegrid_state.numsplatpaths++;
2533 VectorCopy(start, path->point);
2534 VectorScale(diff, ilen, path->step);
2535 VectorCopy(color, path->splatcolor);
2536 VectorCopy(originaldir, path->splatdir);
2537 path->splatsize_current = r_shadow_bouncegrid_state.settings.lightpathsize_initial + r_shadow_bouncegrid_state.settings.lightpathsize_conespread * distancetraveled * r_shadow_bouncegrid_state.ispacing[0];
2538 path->splatsize_perstep = r_shadow_bouncegrid_state.settings.lightpathsize_conespread;
2539 path->splatintensity = VectorLength(color);
2540 path->remainingsplats = numsplats;
2543 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
2545 qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
2552 // see if there are really any lights to render...
2553 if (enable && r_shadow_bouncegrid_static.integer)
2556 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2557 for (lightindex = 0;lightindex < range;lightindex++)
2559 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2560 if (!light || !(light->flags & flag))
2562 rtlight = &light->rtlight;
2563 // when static, we skip styled lights because they tend to change...
2564 if (rtlight->style > 0)
2566 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
2567 if (!VectorLength2(lightcolor))
2577 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
2579 qboolean s = r_shadow_bouncegrid_static.integer != 0;
2580 float spacing = bound(1.0f, s ? r_shadow_bouncegrid_static_spacing.value : r_shadow_bouncegrid_dynamic_spacing.value, 1024.0f);
2581 float quality = bound(0.0001f, (s ? r_shadow_bouncegrid_static_quality.value : r_shadow_bouncegrid_dynamic_quality.value), 1024.0f);
2582 float bounceminimumintensity = s ? r_shadow_bouncegrid_static_bounceminimumintensity.value : r_shadow_bouncegrid_dynamic_bounceminimumintensity.value;
2584 // prevent any garbage in alignment padded areas as we'll be using memcmp
2585 memset(settings, 0, sizeof(*settings));
2587 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
2588 settings->staticmode = s;
2589 settings->blur = r_shadow_bouncegrid_blur.integer != 0;
2590 settings->floatcolors = bound(0, r_shadow_bouncegrid_floatcolors.integer, 2);
2591 settings->lightpathsize_initial = bound(0.0f, r_shadow_bouncegrid_lightpathsize_initial.value, 1024.0f);
2592 settings->lightpathsize_conespread = bound(0.0f, r_shadow_bouncegrid_lightpathsize_conespread.value, 1024.0f);
2593 settings->bounceanglediffuse = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
2594 settings->directionalshading = (s ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_dynamic_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
2595 settings->dlightparticlemultiplier = s ? 0 : r_shadow_bouncegrid_dynamic_dlightparticlemultiplier.value;
2596 settings->hitmodels = s ? false : r_shadow_bouncegrid_dynamic_hitmodels.integer != 0;
2597 settings->includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
2598 settings->lightradiusscale = (s ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_dynamic_lightradiusscale.value);
2599 settings->maxbounce = (s ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_dynamic_maxbounce.integer);
2600 settings->particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
2601 settings->particleintensity = r_shadow_bouncegrid_particleintensity.value * (settings->directionalshading ? 4.0f : 1.0f) * 16384 / (spacing * spacing) / 262144.0f;
2602 settings->maxphotons = s ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_dynamic_maxphotons.integer;
2603 settings->energyperphoton = spacing * spacing / quality;
2604 settings->spacing[0] = spacing;
2605 settings->spacing[1] = spacing;
2606 settings->spacing[2] = spacing;
2607 settings->rng_type = r_shadow_bouncegrid_rng_type.integer;
2608 settings->rng_seed = r_shadow_bouncegrid_rng_seed.integer;
2609 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
2610 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
2611 settings->normalizevectors = r_shadow_bouncegrid_normalizevectors.integer != 0;
2613 // bound the values for sanity
2614 settings->maxphotons = bound(1, settings->maxphotons, 25000000);
2615 settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
2616 settings->maxbounce = bound(0, settings->maxbounce, 16);
2617 settings->spacing[0] = bound(1, settings->spacing[0], 512);
2618 settings->spacing[1] = bound(1, settings->spacing[1], 512);
2619 settings->spacing[2] = bound(1, settings->spacing[2], 512);
2622 static void R_Shadow_BounceGrid_UpdateSpacing(void)
2633 r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
2635 // get the spacing values
2636 spacing[0] = settings->spacing[0];
2637 spacing[1] = settings->spacing[1];
2638 spacing[2] = settings->spacing[2];
2639 ispacing[0] = 1.0f / spacing[0];
2640 ispacing[1] = 1.0f / spacing[1];
2641 ispacing[2] = 1.0f / spacing[2];
2643 // calculate texture size enclosing entire world bounds at the spacing
2644 if (r_refdef.scene.worldmodel)
2648 qboolean bounds_set = false;
2652 // calculate bounds enclosing world lights as they should be noticably tighter
2653 // than the world bounds on maps with unlit monster containers (see e1m7 etc)
2654 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2655 for (lightindex = 0;lightindex < range;lightindex++)
2657 const vec_t *rtlmins, *rtlmaxs;
2659 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2663 rtlight = &light->rtlight;
2664 rtlmins = rtlight->cullmins;
2665 rtlmaxs = rtlight->cullmaxs;
2669 VectorCopy(rtlmins, mins);
2670 VectorCopy(rtlmaxs, maxs);
2675 mins[0] = min(mins[0], rtlmins[0]);
2676 mins[1] = min(mins[1], rtlmins[1]);
2677 mins[2] = min(mins[2], rtlmins[2]);
2678 maxs[0] = max(maxs[0], rtlmaxs[0]);
2679 maxs[1] = max(maxs[1], rtlmaxs[1]);
2680 maxs[2] = max(maxs[2], rtlmaxs[2]);
2684 // limit to no larger than the world bounds
2685 mins[0] = max(mins[0], r_refdef.scene.worldmodel->normalmins[0]);
2686 mins[1] = max(mins[1], r_refdef.scene.worldmodel->normalmins[1]);
2687 mins[2] = max(mins[2], r_refdef.scene.worldmodel->normalmins[2]);
2688 maxs[0] = min(maxs[0], r_refdef.scene.worldmodel->normalmaxs[0]);
2689 maxs[1] = min(maxs[1], r_refdef.scene.worldmodel->normalmaxs[1]);
2690 maxs[2] = min(maxs[2], r_refdef.scene.worldmodel->normalmaxs[2]);
2692 VectorMA(mins, -2.0f, spacing, mins);
2693 VectorMA(maxs, 2.0f, spacing, maxs);
2697 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
2698 VectorSet(maxs, 1048576.0f, 1048576.0f, 1048576.0f);
2700 VectorSubtract(maxs, mins, size);
2701 // now we can calculate the resolution we want
2702 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2703 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2704 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2705 // figure out the exact texture size (honoring power of 2 if required)
2706 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2707 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2708 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2709 if (vid.support.arb_texture_non_power_of_two)
2711 resolution[0] = c[0];
2712 resolution[1] = c[1];
2713 resolution[2] = c[2];
2717 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2718 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2719 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2721 size[0] = spacing[0] * resolution[0];
2722 size[1] = spacing[1] * resolution[1];
2723 size[2] = spacing[2] * resolution[2];
2725 // if dynamic we may or may not want to use the world bounds
2726 // if the dynamic size is smaller than the world bounds, use it instead
2727 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]))
2729 // we know the resolution we want
2730 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
2731 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
2732 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
2733 // now we can calculate the texture size (power of 2 if required)
2734 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2735 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2736 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2737 if (vid.support.arb_texture_non_power_of_two)
2739 resolution[0] = c[0];
2740 resolution[1] = c[1];
2741 resolution[2] = c[2];
2745 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2746 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2747 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2749 size[0] = spacing[0] * resolution[0];
2750 size[1] = spacing[1] * resolution[1];
2751 size[2] = spacing[2] * resolution[2];
2752 // center the rendering on the view
2753 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2754 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2755 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2758 // recalculate the maxs in case the resolution was not satisfactory
2759 VectorAdd(mins, size, maxs);
2761 // check if this changed the texture size
2762 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);
2763 r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
2764 VectorCopy(mins, r_shadow_bouncegrid_state.mins);
2765 VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
2766 VectorCopy(size, r_shadow_bouncegrid_state.size);
2767 VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
2768 VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
2769 VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
2771 // reallocate pixels for this update if needed...
2772 r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
2773 r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
2774 r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
2775 numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
2776 if (r_shadow_bouncegrid_state.numpixels != numpixels)
2778 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
2779 r_shadow_bouncegrid_state.highpixels = NULL;
2780 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2781 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2782 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2783 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2784 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2785 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2786 r_shadow_bouncegrid_state.numpixels = numpixels;
2789 // update the bouncegrid matrix to put it in the world properly
2790 memset(m, 0, sizeof(m));
2791 m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
2792 m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
2793 m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
2794 m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
2795 m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
2796 m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
2798 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
2801 // enumerate world rtlights and sum the overall amount of light in the world,
2802 // from that we can calculate a scaling factor to fairly distribute photons
2803 // to all the lights
2805 // this modifies rtlight->photoncolor and rtlight->photons
2806 static void R_Shadow_BounceGrid_AssignPhotons(r_shadow_bouncegrid_settings_t *settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
2808 float normalphotonscaling;
2809 float photonscaling;
2810 float photonintensity;
2811 float photoncount = 0.0f;
2812 float lightintensity;
2818 unsigned int lightindex;
2821 normalphotonscaling = 1.0f / max(0.0001f, settings->energyperphoton);
2822 for (lightindex = 0;lightindex < range2;lightindex++)
2824 if (lightindex < range)
2826 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2829 rtlight = &light->rtlight;
2830 VectorClear(rtlight->bouncegrid_photoncolor);
2831 rtlight->bouncegrid_photons = 0;
2832 rtlight->bouncegrid_hits = 0;
2833 rtlight->bouncegrid_traces = 0;
2834 rtlight->bouncegrid_effectiveradius = 0;
2835 if (!(light->flags & flag))
2837 if (settings->staticmode)
2839 // when static, we skip styled lights because they tend to change...
2840 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2843 else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
2848 rtlight = r_refdef.scene.lights[lightindex - range];
2849 VectorClear(rtlight->bouncegrid_photoncolor);
2850 rtlight->bouncegrid_photons = 0;
2851 rtlight->bouncegrid_hits = 0;
2852 rtlight->bouncegrid_traces = 0;
2853 rtlight->bouncegrid_effectiveradius = 0;
2855 // draw only visible lights (major speedup)
2856 radius = rtlight->radius * settings->lightradiusscale;
2857 cullmins[0] = rtlight->shadoworigin[0] - radius;
2858 cullmins[1] = rtlight->shadoworigin[1] - radius;
2859 cullmins[2] = rtlight->shadoworigin[2] - radius;
2860 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2861 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2862 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2863 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2864 if (!settings->staticmode)
2866 // skip if the expanded light box does not touch any visible leafs
2867 if (r_refdef.scene.worldmodel
2868 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2869 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2871 // skip if the expanded light box is not visible to traceline
2872 // note that PrepareLight already did this check but for a smaller box, so we
2873 // end up casting more traces per frame per light when using bouncegrid, which
2874 // is probably fine (and they use the same timer)
2875 if (r_shadow_culllights_trace.integer)
2877 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))
2878 rtlight->trace_timer = realtime;
2879 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
2882 // skip if expanded light box is offscreen
2883 if (R_CullBox(cullmins, cullmaxs))
2885 // skip if overall light intensity is zero
2886 if (w * VectorLength2(rtlight->color) == 0.0f)
2889 // a light that does not emit any light before style is applied, can be
2890 // skipped entirely (it may just be a corona)
2891 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2893 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2894 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2895 // skip lights that will emit no photons
2896 if (!VectorLength2(rtlight->bouncegrid_photoncolor))
2898 // shoot particles from this light
2899 // use a calculation for the number of particles that will not
2900 // vary with lightstyle, otherwise we get randomized particle
2901 // distribution, the seeded random is only consistent for a
2902 // consistent number of particles on this light...
2903 s = rtlight->radius;
2904 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2905 if (lightindex >= range)
2906 lightintensity *= settings->dlightparticlemultiplier;
2907 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2908 photoncount += rtlight->bouncegrid_photons;
2909 VectorScale(rtlight->bouncegrid_photoncolor, settings->particleintensity * settings->energyperphoton, rtlight->bouncegrid_photoncolor);
2910 // if the lightstyle happens to be off right now, we can skip actually
2911 // firing the photons, but we did have to count them in the total.
2912 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2913 // rtlight->bouncegrid_photons = 0;
2915 // the user provided an energyperphoton value which we try to use
2916 // if that results in too many photons to shoot this frame, then we cap it
2917 // which causes photons to appear/disappear from frame to frame, so we don't
2918 // like doing that in the typical case
2919 photonscaling = 1.0f;
2920 photonintensity = 1.0f;
2921 if (photoncount > settings->maxphotons)
2923 photonscaling = settings->maxphotons / photoncount;
2924 photonintensity = 1.0f / photonscaling;
2927 // modify the lights to reflect our computed scaling
2928 for (lightindex = 0; lightindex < range2; lightindex++)
2930 if (lightindex < range)
2932 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2935 rtlight = &light->rtlight;
2938 rtlight = r_refdef.scene.lights[lightindex - range];
2939 rtlight->bouncegrid_photons *= photonscaling;
2940 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2944 static int R_Shadow_BounceGrid_SplatPathCompare(const void *pa, const void *pb)
2946 r_shadow_bouncegrid_splatpath_t *a = (r_shadow_bouncegrid_splatpath_t *)pa;
2947 r_shadow_bouncegrid_splatpath_t *b = (r_shadow_bouncegrid_splatpath_t *)pb;
2948 // we only really care about sorting by Z
2949 if (a->point[2] < b->point[2])
2951 if (a->point[2] > b->point[2])
2956 static void R_Shadow_BounceGrid_ClearPixels(void)
2958 // clear the highpixels array we'll be accumulating into
2959 if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2960 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2961 if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2962 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2963 r_shadow_bouncegrid_state.highpixels_index = 0;
2964 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2965 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2968 static void R_Shadow_BounceGrid_PerformSplats(void)
2970 r_shadow_bouncegrid_splatpath_t *splatpaths = r_shadow_bouncegrid_state.splatpaths;
2971 r_shadow_bouncegrid_splatpath_t *splatpath;
2972 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2973 int numsplatpaths = r_shadow_bouncegrid_state.numsplatpaths;
2978 vec_t lightpathsize_current;
2979 vec_t lightpathsize_perstep;
2980 float splatcolor[32];
2982 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2983 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2987 // hush warnings about uninitialized data - pixelbands doesn't change but...
2988 memset(splatcolor, 0, sizeof(splatcolor));
2990 // we use this a lot, so get a local copy
2991 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2993 // sort the splats before we execute them, to reduce cache misses
2994 if (r_shadow_bouncegrid_sortlightpaths.integer)
2995 qsort(splatpaths, numsplatpaths, sizeof(*splatpaths), R_Shadow_BounceGrid_SplatPathCompare);
2997 splatpath = splatpaths;
2998 for (splatindex = 0;splatindex < numsplatpaths;splatindex++, splatpath++)
3000 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
3001 // accumulate average shotcolor
3002 VectorCopy(splatpath->splatdir, dir);
3003 splatcolor[ 0] = splatpath->splatcolor[0];
3004 splatcolor[ 1] = splatpath->splatcolor[1];
3005 splatcolor[ 2] = splatpath->splatcolor[2];
3006 splatcolor[ 3] = 0.0f;
3009 // store bentnormal in case the shader has a use for it,
3010 // bentnormal is an intensity-weighted average of the directions,
3011 // and will be normalized on conversion to texture pixels.
3012 splatcolor[ 4] = dir[0] * splatpath->splatintensity;
3013 splatcolor[ 5] = dir[1] * splatpath->splatintensity;
3014 splatcolor[ 6] = dir[2] * splatpath->splatintensity;
3015 splatcolor[ 7] = splatpath->splatintensity;
3016 // for each color component (R, G, B) calculate the amount that a
3017 // direction contributes
3018 splatcolor[ 8] = splatcolor[0] * max(0.0f, dir[0]);
3019 splatcolor[ 9] = splatcolor[0] * max(0.0f, dir[1]);
3020 splatcolor[10] = splatcolor[0] * max(0.0f, dir[2]);
3021 splatcolor[11] = 0.0f;
3022 splatcolor[12] = splatcolor[1] * max(0.0f, dir[0]);
3023 splatcolor[13] = splatcolor[1] * max(0.0f, dir[1]);
3024 splatcolor[14] = splatcolor[1] * max(0.0f, dir[2]);
3025 splatcolor[15] = 0.0f;
3026 splatcolor[16] = splatcolor[2] * max(0.0f, dir[0]);
3027 splatcolor[17] = splatcolor[2] * max(0.0f, dir[1]);
3028 splatcolor[18] = splatcolor[2] * max(0.0f, dir[2]);
3029 splatcolor[19] = 0.0f;
3030 // and do the same for negative directions
3031 splatcolor[20] = splatcolor[0] * max(0.0f, -dir[0]);
3032 splatcolor[21] = splatcolor[0] * max(0.0f, -dir[1]);
3033 splatcolor[22] = splatcolor[0] * max(0.0f, -dir[2]);
3034 splatcolor[23] = 0.0f;
3035 splatcolor[24] = splatcolor[1] * max(0.0f, -dir[0]);
3036 splatcolor[25] = splatcolor[1] * max(0.0f, -dir[1]);
3037 splatcolor[26] = splatcolor[1] * max(0.0f, -dir[2]);
3038 splatcolor[27] = 0.0f;
3039 splatcolor[28] = splatcolor[2] * max(0.0f, -dir[0]);
3040 splatcolor[29] = splatcolor[2] * max(0.0f, -dir[1]);
3041 splatcolor[30] = splatcolor[2] * max(0.0f, -dir[2]);
3042 splatcolor[31] = 0.0f;
3044 // calculate the number of steps we need to traverse this distance
3045 VectorCopy(splatpath->point, steppos);
3046 VectorCopy(splatpath->step, stepdelta);
3047 numsteps = splatpath->remainingsplats;
3048 lightpathsize_current = splatpath->splatsize_current + 1.0f; // add 1.0 for the gradient fade around the sphere
3049 lightpathsize_perstep = splatpath->splatsize_perstep;
3050 for (step = 0;step < numsteps;step++)
3052 // the middle row/column/layer of each splat are full intensity
3055 if (lightpathsize_current > MAXBOUNCEGRIDSPLATSIZE)
3056 lightpathsize_current = MAXBOUNCEGRIDSPLATSIZE;
3057 splatmins[0] = max(1.0f, steppos[0] - lightpathsize_current * 0.5f);
3058 splatmins[1] = max(1.0f, steppos[1] - lightpathsize_current * 0.5f);
3059 splatmins[2] = max(1.0f, steppos[2] - lightpathsize_current * 0.5f);
3060 splatmaxs[0] = min(steppos[0] + lightpathsize_current * 0.5f, resolution[0] - 1.0f);
3061 splatmaxs[1] = min(steppos[1] + lightpathsize_current * 0.5f, resolution[1] - 1.0f);
3062 splatmaxs[2] = min(steppos[2] + lightpathsize_current * 0.5f, resolution[2] - 1.0f);
3063 if (splatmaxs[0] > splatmins[0] && splatmaxs[1] > splatmins[1] && splatmaxs[2] > splatmins[2])
3065 // it is within bounds... do the real work now
3066 int xi, yi, zi, band, row;
3070 float colorscale = 1.0f / lightpathsize_current;
3071 r_refdef.stats[r_stat_bouncegrid_splats]++;
3072 // accumulate light onto the pixels
3073 for (zi = (int)floor(splatmins[2]);zi < splatmaxs[2];zi++)
3075 pixelpos[2] = zi + 0.5f;
3076 for (yi = (int)floor(splatmins[1]); yi < splatmaxs[1]; yi++)
3078 pixelpos[1] = yi + 0.5f;
3079 row = (zi*resolution[1] + yi)*resolution[0];
3080 for (xi = (int)floor(splatmins[0]); xi < splatmaxs[0]; xi++)
3082 pixelpos[0] = xi + 0.5f;
3083 // simple radial antialiased sphere - linear gradient fade over 1 pixel from the edge
3084 w = lightpathsize_current - VectorDistance(pixelpos, steppos);
3090 p = highpixels + 4 * (row + xi);
3091 for (band = 0; band < pixelbands; band++, p += pixelsperband * 4)
3093 // add to the pixel color
3094 p[0] += splatcolor[band * 4 + 0] * w;
3095 p[1] += splatcolor[band * 4 + 1] * w;
3096 p[2] += splatcolor[band * 4 + 2] * w;
3097 p[3] += splatcolor[band * 4 + 3] * w;
3104 VectorAdd(steppos, stepdelta, steppos);
3105 lightpathsize_current += lightpathsize_perstep;
3110 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
3112 const float *inpixel;
3114 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
3117 unsigned int x, y, z;
3118 unsigned int resolution[3];
3119 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3120 for (pixelband = 0;pixelband < pixelbands;pixelband++)
3122 for (z = 1;z < resolution[2]-1;z++)
3124 for (y = 1;y < resolution[1]-1;y++)
3127 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3128 inpixel = inpixels + 4*index;
3129 outpixel = outpixels + 4*index;
3130 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
3132 outpixel[0] = (inpixel[0] + inpixel[ off] + inpixel[0-off]) * (1.0f / 3.0);
3133 outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
3134 outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
3135 outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
3142 static void R_Shadow_BounceGrid_BlurPixels(void)
3145 unsigned int resolution[3];
3147 if (!r_shadow_bouncegrid_state.settings.blur)
3150 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3152 pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3153 pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
3154 pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3155 pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
3158 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
3160 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
3162 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
3164 // toggle the state, highpixels now points to pixels[3] result
3165 r_shadow_bouncegrid_state.highpixels_index ^= 1;
3166 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3169 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
3171 int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
3172 unsigned char *pixelsbgra8 = NULL;
3173 unsigned char *pixelbgra8;
3174 unsigned short *pixelsrgba16f = NULL;
3175 unsigned short *pixelrgba16f;
3176 float *pixelsrgba32f = NULL;
3177 float *highpixels = r_shadow_bouncegrid_state.highpixels;
3180 unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
3181 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
3182 unsigned int pixelband;
3183 unsigned int x, y, z;
3184 unsigned int index, bandindex;
3185 unsigned int resolution[3];
3187 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3189 if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
3191 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3192 r_shadow_bouncegrid_state.texture = NULL;
3195 // if bentnormals exist, we need to normalize and bias them for the shader
3199 for (z = 0;z < resolution[2]-1;z++)
3201 for (y = 0;y < resolution[1]-1;y++)
3204 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3205 highpixel = highpixels + 4*index;
3206 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3208 // only convert pixels that were hit by photons
3209 if (highpixel[3] != 0.0f)
3210 VectorNormalize(highpixel);
3211 VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
3212 highpixel[pixelsperband * 4 + 3] = 1.0f;
3218 // start by clearing the pixels array - we won't be writing to all of it
3220 // then process only the pixels that have at least some color, skipping
3221 // the higher bands for speed on pixels that are black
3222 switch (floatcolors)
3225 if (r_shadow_bouncegrid_state.u8pixels == NULL)
3226 r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
3227 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
3228 for (pixelband = 0;pixelband < pixelbands;pixelband++)
3231 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
3233 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
3235 for (z = 1;z < resolution[2]-1;z++)
3237 for (y = 1;y < resolution[1]-1;y++)
3241 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3242 highpixel = highpixels + 4*index;
3243 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3245 // only convert pixels that were hit by photons
3246 if (VectorLength2(highpixel))
3248 // normalize the bentnormal now
3251 VectorNormalize(highpixel + pixelsperband * 4);
3252 highpixel[pixelsperband * 4 + 3] = 1.0f;
3254 // process all of the pixelbands for this pixel
3255 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3257 pixelbgra8 = pixelsbgra8 + 4*bandindex;
3258 bandpixel = highpixels + 4*bandindex;
3259 c[0] = (int)(bandpixel[0]*256.0f);
3260 c[1] = (int)(bandpixel[1]*256.0f);
3261 c[2] = (int)(bandpixel[2]*256.0f);
3262 c[3] = (int)(bandpixel[3]*256.0f);
3263 pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
3264 pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
3265 pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
3266 pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
3273 if (!r_shadow_bouncegrid_state.createtexture)
3274 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3276 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);
3279 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
3280 r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3281 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
3282 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3283 for (z = 1;z < resolution[2]-1;z++)
3285 for (y = 1;y < resolution[1]-1;y++)
3289 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3290 highpixel = highpixels + 4*index;
3291 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3293 // only convert pixels that were hit by photons
3294 if (VectorLength2(highpixel))
3296 // process all of the pixelbands for this pixel
3297 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3299 // time to have fun with IEEE 754 bit hacking...
3302 unsigned int raw[4];
3304 pixelrgba16f = pixelsrgba16f + 4*bandindex;
3305 bandpixel = highpixels + 4*bandindex;
3306 VectorCopy4(bandpixel, u.f);
3307 VectorCopy4(u.raw, c);
3308 // this math supports negative numbers, snaps denormals to zero
3309 //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
3310 //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
3311 //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
3312 //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
3313 // this math does not support negative
3314 pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
3315 pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
3316 pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
3317 pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
3324 if (!r_shadow_bouncegrid_state.createtexture)
3325 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3327 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);
3330 // our native format happens to match, so this is easy.
3331 pixelsrgba32f = highpixels;
3333 if (!r_shadow_bouncegrid_state.createtexture)
3334 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3336 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);
3340 r_shadow_bouncegrid_state.lastupdatetime = realtime;
3343 static void R_Shadow_BounceGrid_TracePhotons(r_shadow_bouncegrid_settings_t settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
3345 vec3_t bouncerandom[10];
3348 int hitsupercontentsmask;
3349 int skipsupercontentsmask;
3350 int skipmaterialflagsmask;
3354 float bounceminimumintensity2;
3356 //trace_t cliptrace2;
3357 //trace_t cliptrace3;
3358 unsigned int lightindex;
3360 randomseed_t randomseed;
3362 vec3_t baseshotcolor;
3368 vec_t distancetraveled;
3372 // compute a seed for the unstable random modes
3373 Math_RandomSeed_FromInts(&randomseed, 0, 0, 0, realtime * 1000.0);
3374 seed = realtime * 1000.0;
3376 r_shadow_bouncegrid_state.numsplatpaths = 0;
3378 // figure out what we want to interact with
3379 if (settings.hitmodels)
3380 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
3382 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
3383 skipsupercontentsmask = 0;
3384 skipmaterialflagsmask = MATERIALFLAGMASK_TRANSLUCENT;
3385 maxbounce = settings.maxbounce;
3387 for (lightindex = 0;lightindex < range2;lightindex++)
3389 if (lightindex < range)
3391 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3394 rtlight = &light->rtlight;
3397 rtlight = r_refdef.scene.lights[lightindex - range];
3398 // note that this code used to keep track of residual photons and
3399 // distribute them evenly to achieve exactly a desired photon count,
3400 // but that caused unwanted flickering in dynamic mode
3401 shootparticles = (int)floor(rtlight->bouncegrid_photons);
3402 // skip if we won't be shooting any photons
3403 if (!shootparticles)
3405 radius = rtlight->radius * settings.lightradiusscale;
3406 //s = settings.particleintensity / shootparticles;
3407 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
3408 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
3409 if (VectorLength2(baseshotcolor) <= 0.0f)
3411 r_refdef.stats[r_stat_bouncegrid_lights]++;
3412 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
3413 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
3414 bounceminimumintensity2 = VectorLength(baseshotcolor) * settings.bounceminimumintensity2;
3416 // for seeded random we start the RNG with the position of the light
3417 if (settings.rng_seed >= 0)
3425 u.f[0] = rtlight->shadoworigin[0];
3426 u.f[1] = rtlight->shadoworigin[1];
3427 u.f[2] = rtlight->shadoworigin[2];
3429 switch (settings.rng_type)
3433 // we have to shift the seed provided by the user because the result must be odd
3434 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3] ^ (settings.rng_seed << 1));
3437 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3] ^ settings.rng_seed;
3442 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
3444 VectorCopy(baseshotcolor, shotcolor);
3445 VectorCopy(rtlight->shadoworigin, clipstart);
3446 switch (settings.rng_type)
3450 VectorLehmerRandom(&randomseed, clipend);
3451 if (settings.bounceanglediffuse)
3453 // we want random to be stable, so we still have to do all the random we would have done
3454 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3455 VectorLehmerRandom(&randomseed, bouncerandom[bouncecount]);
3459 VectorCheeseRandom(seed, clipend);
3460 if (settings.bounceanglediffuse)
3462 // we want random to be stable, so we still have to do all the random we would have done
3463 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3464 VectorCheeseRandom(seed, bouncerandom[bouncecount]);
3469 // we want a uniform distribution spherically, not merely within the sphere
3470 if (settings.normalizevectors)
3471 VectorNormalize(clipend);
3473 VectorMA(clipstart, radius, clipend, clipend);
3474 distancetraveled = 0.0f;
3475 for (bouncecount = 0;;bouncecount++)
3477 r_refdef.stats[r_stat_bouncegrid_traces]++;
3478 rtlight->bouncegrid_traces++;
3479 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
3480 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
3481 if (settings.staticmode || settings.rng_seed < 0)
3483 // static mode fires a LOT of rays but none of them are identical, so they are not cached
3484 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
3485 cliptrace = CL_TraceLine(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), NULL, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, collision_extendmovelength.value, true, false, NULL, true, true);
3489 // dynamic mode fires many rays and most will match the cache from the previous frame
3490 cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
3492 if (bouncecount > 0 || settings.includedirectlighting)
3495 VectorCopy(cliptrace.endpos, hitpos);
3496 R_Shadow_BounceGrid_AddSplatPath(clipstart, hitpos, shotcolor, distancetraveled);
3498 distancetraveled += VectorDistance(clipstart, cliptrace.endpos);
3499 s = VectorDistance(rtlight->shadoworigin, cliptrace.endpos);
3500 if (rtlight->bouncegrid_effectiveradius < s)
3501 rtlight->bouncegrid_effectiveradius = s;
3502 if (cliptrace.fraction >= 1.0f)
3504 r_refdef.stats[r_stat_bouncegrid_hits]++;
3505 rtlight->bouncegrid_hits++;
3506 if (bouncecount >= maxbounce)
3508 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
3509 // also clamp the resulting color to never add energy, even if the user requests extreme values
3510 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
3511 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
3513 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
3514 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
3515 surfcolor[0] = min(surfcolor[0], 1.0f);
3516 surfcolor[1] = min(surfcolor[1], 1.0f);
3517 surfcolor[2] = min(surfcolor[2], 1.0f);
3518 VectorMultiply(shotcolor, surfcolor, shotcolor);
3519 if (VectorLength2(shotcolor) <= bounceminimumintensity2)
3521 r_refdef.stats[r_stat_bouncegrid_bounces]++;
3522 if (settings.bounceanglediffuse)
3524 // random direction, primarily along plane normal
3525 s = VectorDistance(cliptrace.endpos, clipend);
3526 VectorMA(cliptrace.plane.normal, 0.95f, bouncerandom[bouncecount], clipend);
3527 VectorNormalize(clipend);
3528 VectorScale(clipend, s, clipend);
3532 // reflect the remaining portion of the line across plane normal
3533 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
3534 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
3536 // calculate the new line start and end
3537 VectorCopy(cliptrace.endpos, clipstart);
3538 VectorAdd(clipstart, clipend, clipend);
3544 void R_Shadow_UpdateBounceGridTexture(void)
3546 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3547 r_shadow_bouncegrid_settings_t settings;
3548 qboolean enable = false;
3549 qboolean settingschanged;
3550 unsigned int range; // number of world lights
3551 unsigned int range1; // number of dynamic lights (or zero if disabled)
3552 unsigned int range2; // range+range1
3554 enable = R_Shadow_BounceGrid_CheckEnable(flag);
3556 R_Shadow_BounceGrid_GenerateSettings(&settings);
3558 // changing intensity does not require an update
3559 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
3561 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
3563 // when settings change, we free everything as it is just simpler that way.
3564 if (settingschanged || !enable)
3566 // not enabled, make sure we free anything we don't need anymore.
3567 if (r_shadow_bouncegrid_state.texture)
3569 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3570 r_shadow_bouncegrid_state.texture = NULL;
3572 r_shadow_bouncegrid_state.highpixels = NULL;
3573 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
3574 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
3575 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
3576 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
3577 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
3578 r_shadow_bouncegrid_state.maxsplatpaths = 0;
3579 r_shadow_bouncegrid_state.numpixels = 0;
3580 r_shadow_bouncegrid_state.directional = false;
3586 // if all the settings seem identical to the previous update, return
3587 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
3590 // store the new settings
3591 r_shadow_bouncegrid_state.settings = settings;
3593 R_Shadow_BounceGrid_UpdateSpacing();
3595 // get the range of light numbers we'll be looping over:
3596 // range = static lights
3597 // range1 = dynamic lights (optional)
3598 // range2 = range + range1
3599 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3600 range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
3601 range2 = range + range1;
3603 // calculate weighting factors for distributing photons among the lights
3604 R_Shadow_BounceGrid_AssignPhotons(&settings, range, range1, range2, flag);
3606 // trace the photons from lights and accumulate illumination
3607 R_Shadow_BounceGrid_TracePhotons(settings, range, range1, range2, flag);
3609 // clear the texture
3610 R_Shadow_BounceGrid_ClearPixels();
3612 // accumulate the light splatting into texture
3613 R_Shadow_BounceGrid_PerformSplats();
3615 // apply a mild blur filter to the texture
3616 R_Shadow_BounceGrid_BlurPixels();
3618 // convert the pixels to lower precision and upload the texture
3619 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
3621 // after we compute the static lighting we don't need to keep the highpixels array around
3622 if (settings.staticmode)
3624 r_shadow_bouncegrid_state.highpixels = NULL;
3625 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
3626 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
3627 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
3628 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
3629 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
3630 r_shadow_bouncegrid_state.maxsplatpaths = 0;
3634 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
3636 R_Shadow_RenderMode_Reset();
3637 GL_BlendFunc(GL_ONE, GL_ONE);
3638 GL_DepthRange(0, 1);
3639 GL_DepthTest(r_showshadowvolumes.integer < 2);
3640 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
3641 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
3642 GL_CullFace(GL_NONE);
3643 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
3646 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
3648 R_Shadow_RenderMode_Reset();
3649 GL_BlendFunc(GL_ONE, GL_ONE);
3650 GL_DepthRange(0, 1);
3651 GL_DepthTest(r_showlighting.integer < 2);
3652 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
3654 GL_DepthFunc(GL_EQUAL);
3655 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
3656 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
3659 void R_Shadow_RenderMode_End(void)
3661 R_Shadow_RenderMode_Reset();
3662 R_Shadow_RenderMode_ActiveLight(NULL);
3664 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3665 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3668 int bboxedges[12][2] =
3687 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
3689 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
3691 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
3692 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
3693 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
3694 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
3697 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
3698 return true; // invisible
3699 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
3700 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
3701 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
3702 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
3703 r_refdef.stats[r_stat_lights_scissored]++;
3707 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
3710 const float *vertex3f;
3711 const float *normal3f;
3713 float dist, dot, distintensity, shadeintensity, v[3], n[3];
3714 switch (r_shadow_rendermode)
3716 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3717 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3718 if (VectorLength2(diffusecolor) > 0)
3720 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)
3722 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3723 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3724 if ((dot = DotProduct(n, v)) < 0)
3726 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3727 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
3730 VectorCopy(ambientcolor, color4f);
3731 if (r_refdef.fogenabled)
3734 f = RSurf_FogVertex(vertex3f);
3735 VectorScale(color4f, f, color4f);
3742 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3744 VectorCopy(ambientcolor, color4f);
3745 if (r_refdef.fogenabled)
3748 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3749 f = RSurf_FogVertex(vertex3f);
3750 VectorScale(color4f + 4*i, f, color4f);
3756 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3757 if (VectorLength2(diffusecolor) > 0)
3759 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)
3761 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3762 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3764 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3765 if ((dot = DotProduct(n, v)) < 0)
3767 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3768 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3769 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3770 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3774 color4f[0] = ambientcolor[0] * distintensity;
3775 color4f[1] = ambientcolor[1] * distintensity;
3776 color4f[2] = ambientcolor[2] * distintensity;
3778 if (r_refdef.fogenabled)
3781 f = RSurf_FogVertex(vertex3f);
3782 VectorScale(color4f, f, color4f);
3786 VectorClear(color4f);
3792 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3794 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3795 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3797 color4f[0] = ambientcolor[0] * distintensity;
3798 color4f[1] = ambientcolor[1] * distintensity;
3799 color4f[2] = ambientcolor[2] * distintensity;
3800 if (r_refdef.fogenabled)
3803 f = RSurf_FogVertex(vertex3f);
3804 VectorScale(color4f, f, color4f);
3808 VectorClear(color4f);
3813 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3814 if (VectorLength2(diffusecolor) > 0)
3816 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)
3818 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3819 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3821 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3822 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3823 if ((dot = DotProduct(n, v)) < 0)
3825 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3826 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3827 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3828 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3832 color4f[0] = ambientcolor[0] * distintensity;
3833 color4f[1] = ambientcolor[1] * distintensity;
3834 color4f[2] = ambientcolor[2] * distintensity;
3836 if (r_refdef.fogenabled)
3839 f = RSurf_FogVertex(vertex3f);
3840 VectorScale(color4f, f, color4f);
3844 VectorClear(color4f);
3850 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3852 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3853 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3855 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3856 color4f[0] = ambientcolor[0] * distintensity;
3857 color4f[1] = ambientcolor[1] * distintensity;
3858 color4f[2] = ambientcolor[2] * distintensity;
3859 if (r_refdef.fogenabled)
3862 f = RSurf_FogVertex(vertex3f);
3863 VectorScale(color4f, f, color4f);
3867 VectorClear(color4f);
3877 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3879 // used to display how many times a surface is lit for level design purposes
3880 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3881 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3885 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const float ambientcolor[3], const float diffusecolor[3], const float specularcolor[3])
3887 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3888 R_SetupShader_Surface(ambientcolor, diffusecolor, specularcolor, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
3892 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3899 int newnumtriangles;
3903 int maxtriangles = 1024;
3904 int newelements[1024*3];
3905 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3906 for (renders = 0;renders < 4;renders++)
3911 newnumtriangles = 0;
3913 // due to low fillrate on the cards this vertex lighting path is
3914 // designed for, we manually cull all triangles that do not
3915 // contain a lit vertex
3916 // this builds batches of triangles from multiple surfaces and
3917 // renders them at once
3918 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3920 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3922 if (newnumtriangles)
3924 newfirstvertex = min(newfirstvertex, e[0]);
3925 newlastvertex = max(newlastvertex, e[0]);
3929 newfirstvertex = e[0];
3930 newlastvertex = e[0];
3932 newfirstvertex = min(newfirstvertex, e[1]);
3933 newlastvertex = max(newlastvertex, e[1]);
3934 newfirstvertex = min(newfirstvertex, e[2]);
3935 newlastvertex = max(newlastvertex, e[2]);
3941 if (newnumtriangles >= maxtriangles)
3943 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3944 newnumtriangles = 0;
3950 if (newnumtriangles >= 1)
3952 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3955 // if we couldn't find any lit triangles, exit early
3958 // now reduce the intensity for the next overbright pass
3959 // we have to clamp to 0 here incase the drivers have improper
3960 // handling of negative colors
3961 // (some old drivers even have improper handling of >1 color)
3963 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3965 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3967 c[0] = max(0, c[0] - 1);
3968 c[1] = max(0, c[1] - 1);
3969 c[2] = max(0, c[2] - 1);
3981 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const float ambientcolor[3], const float diffusecolor[3])
3983 // OpenGL 1.1 path (anything)
3984 float ambientcolorbase[3], diffusecolorbase[3];
3985 float ambientcolorpants[3], diffusecolorpants[3];
3986 float ambientcolorshirt[3], diffusecolorshirt[3];
3987 const float *surfacepants = rsurface.texture->render_colormap_pants;
3988 const float *surfaceshirt = rsurface.texture->render_colormap_shirt;
3989 rtexture_t *basetexture = rsurface.texture->basetexture;
3990 rtexture_t *pantstexture = rsurface.texture->pantstexture;
3991 rtexture_t *shirttexture = rsurface.texture->shirttexture;
3992 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3993 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3994 VectorCopy(ambientcolor, ambientcolorbase);
3995 VectorCopy(diffusecolor, diffusecolorbase);
3996 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3997 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3998 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3999 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
4000 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (VectorLength2(diffusecolor) > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
4001 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
4002 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4003 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
4004 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
4005 R_Mesh_TexBind(0, basetexture);
4006 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
4007 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
4008 switch(r_shadow_rendermode)
4010 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
4011 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
4012 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
4013 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
4014 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4016 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
4017 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
4018 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
4019 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
4020 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4022 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
4023 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
4024 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
4025 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
4026 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4028 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
4033 //R_Mesh_TexBind(0, basetexture);
4034 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
4037 R_Mesh_TexBind(0, pantstexture);
4038 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
4042 R_Mesh_TexBind(0, shirttexture);
4043 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
4047 extern cvar_t gl_lightmaps;
4048 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
4051 float ambientcolor[3], diffusecolor[3], specularcolor[3];
4052 VectorM(rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient, rsurface.texture->render_rtlight_diffuse, ambientcolor);
4053 VectorM(rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient), rsurface.texture->render_rtlight_diffuse, diffusecolor);
4054 VectorM(rsurface.rtlight->specularscale, rsurface.texture->render_rtlight_specular, specularcolor);
4055 if (!r_shadow_usenormalmap.integer)
4057 VectorMAM(1.0f, ambientcolor, 1.0f, diffusecolor, ambientcolor);
4058 VectorClear(diffusecolor);
4059 VectorClear(specularcolor);
4061 VectorMultiply(ambientcolor, rsurface.rtlight->currentcolor, ambientcolor);
4062 VectorMultiply(diffusecolor, rsurface.rtlight->currentcolor, diffusecolor);
4063 VectorMultiply(specularcolor, rsurface.rtlight->currentcolor, specularcolor);
4064 if (VectorLength2(ambientcolor) + VectorLength2(diffusecolor) + VectorLength2(specularcolor) < (1.0f / 1048576.0f))
4066 negated = (rsurface.rtlight->currentcolor[0] + rsurface.rtlight->currentcolor[1] + rsurface.rtlight->currentcolor[2] < 0) && vid.support.ext_blend_subtract;
4069 VectorNegate(ambientcolor, ambientcolor);
4070 VectorNegate(diffusecolor, diffusecolor);
4071 VectorNegate(specularcolor, specularcolor);
4072 GL_BlendEquationSubtract(true);
4074 RSurf_SetupDepthAndCulling();
4075 switch (r_shadow_rendermode)
4077 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
4078 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
4079 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
4081 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
4082 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, ambientcolor, diffusecolor, specularcolor);
4084 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
4085 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
4086 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
4087 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
4088 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, ambientcolor, diffusecolor);
4091 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
4095 GL_BlendEquationSubtract(false);
4098 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)
4100 matrix4x4_t tempmatrix = *matrix;
4101 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
4103 // if this light has been compiled before, free the associated data
4104 R_RTLight_Uncompile(rtlight);
4106 // clear it completely to avoid any lingering data
4107 memset(rtlight, 0, sizeof(*rtlight));
4109 // copy the properties
4110 rtlight->matrix_lighttoworld = tempmatrix;
4111 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
4112 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
4113 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
4114 VectorCopy(color, rtlight->color);
4115 rtlight->cubemapname[0] = 0;
4116 if (cubemapname && cubemapname[0])
4117 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
4118 rtlight->shadow = shadow;
4119 rtlight->corona = corona;
4120 rtlight->style = style;
4121 rtlight->isstatic = isstatic;
4122 rtlight->coronasizescale = coronasizescale;
4123 rtlight->ambientscale = ambientscale;
4124 rtlight->diffusescale = diffusescale;
4125 rtlight->specularscale = specularscale;
4126 rtlight->flags = flags;
4128 // compute derived data
4129 //rtlight->cullradius = rtlight->radius;
4130 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
4131 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
4132 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
4133 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
4134 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
4135 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
4136 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
4139 // compiles rtlight geometry
4140 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
4141 void R_RTLight_Compile(rtlight_t *rtlight)
4144 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
4145 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
4146 entity_render_t *ent = r_refdef.scene.worldentity;
4147 dp_model_t *model = r_refdef.scene.worldmodel;
4148 unsigned char *data;
4151 // compile the light
4152 rtlight->compiled = true;
4153 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
4154 rtlight->static_numleafs = 0;
4155 rtlight->static_numleafpvsbytes = 0;
4156 rtlight->static_leaflist = NULL;
4157 rtlight->static_leafpvs = NULL;
4158 rtlight->static_numsurfaces = 0;
4159 rtlight->static_surfacelist = NULL;
4160 rtlight->static_shadowmap_receivers = 0x3F;
4161 rtlight->static_shadowmap_casters = 0x3F;
4162 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
4163 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
4164 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
4165 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
4166 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
4167 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
4169 if (model && model->GetLightInfo)
4171 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
4172 r_shadow_compilingrtlight = rtlight;
4173 R_FrameData_SetMark();
4174 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);
4175 R_FrameData_ReturnToMark();
4176 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
4177 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
4178 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
4179 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
4180 rtlight->static_numsurfaces = numsurfaces;
4181 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
4182 rtlight->static_numleafs = numleafs;
4183 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
4184 rtlight->static_numleafpvsbytes = numleafpvsbytes;
4185 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
4186 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
4187 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
4188 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
4189 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
4190 if (rtlight->static_numsurfaces)
4191 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
4192 if (rtlight->static_numleafs)
4193 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
4194 if (rtlight->static_numleafpvsbytes)
4195 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
4196 if (rtlight->static_numshadowtrispvsbytes)
4197 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
4198 if (rtlight->static_numlighttrispvsbytes)
4199 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
4200 R_FrameData_SetMark();
4201 switch (rtlight->shadowmode)
4203 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4204 if (model->CompileShadowMap && rtlight->shadow)
4205 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
4208 if (model->CompileShadowVolume && rtlight->shadow)
4209 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
4212 R_FrameData_ReturnToMark();
4213 // now we're done compiling the rtlight
4214 r_shadow_compilingrtlight = NULL;
4218 // use smallest available cullradius - box radius or light radius
4219 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
4220 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
4222 shadowzpasstris = 0;
4223 if (rtlight->static_meshchain_shadow_zpass)
4224 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
4225 shadowzpasstris += mesh->numtriangles;
4227 shadowzfailtris = 0;
4228 if (rtlight->static_meshchain_shadow_zfail)
4229 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
4230 shadowzfailtris += mesh->numtriangles;
4233 if (rtlight->static_numlighttrispvsbytes)
4234 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
4235 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
4239 if (rtlight->static_numshadowtrispvsbytes)
4240 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
4241 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
4244 if (developer_extra.integer)
4245 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);
4248 void R_RTLight_Uncompile(rtlight_t *rtlight)
4250 if (rtlight->compiled)
4252 if (rtlight->static_meshchain_shadow_zpass)
4253 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
4254 rtlight->static_meshchain_shadow_zpass = NULL;
4255 if (rtlight->static_meshchain_shadow_zfail)
4256 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
4257 rtlight->static_meshchain_shadow_zfail = NULL;
4258 if (rtlight->static_meshchain_shadow_shadowmap)
4259 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
4260 rtlight->static_meshchain_shadow_shadowmap = NULL;
4261 // these allocations are grouped
4262 if (rtlight->static_surfacelist)
4263 Mem_Free(rtlight->static_surfacelist);
4264 rtlight->static_numleafs = 0;
4265 rtlight->static_numleafpvsbytes = 0;
4266 rtlight->static_leaflist = NULL;
4267 rtlight->static_leafpvs = NULL;
4268 rtlight->static_numsurfaces = 0;
4269 rtlight->static_surfacelist = NULL;
4270 rtlight->static_numshadowtrispvsbytes = 0;
4271 rtlight->static_shadowtrispvs = NULL;
4272 rtlight->static_numlighttrispvsbytes = 0;
4273 rtlight->static_lighttrispvs = NULL;
4274 rtlight->compiled = false;
4278 void R_Shadow_UncompileWorldLights(void)
4282 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4283 for (lightindex = 0;lightindex < range;lightindex++)
4285 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4288 R_RTLight_Uncompile(&light->rtlight);
4292 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
4296 // reset the count of frustum planes
4297 // see rtlight->cached_frustumplanes definition for how much this array
4299 rtlight->cached_numfrustumplanes = 0;
4301 if (r_trippy.integer)
4304 // haven't implemented a culling path for ortho rendering
4305 if (!r_refdef.view.useperspective)
4307 // check if the light is on screen and copy the 4 planes if it is
4308 for (i = 0;i < 4;i++)
4309 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4312 for (i = 0;i < 4;i++)
4313 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4318 // generate a deformed frustum that includes the light origin, this is
4319 // used to cull shadow casting surfaces that can not possibly cast a
4320 // shadow onto the visible light-receiving surfaces, which can be a
4323 // if the light origin is onscreen the result will be 4 planes exactly
4324 // if the light origin is offscreen on only one axis the result will
4325 // be exactly 5 planes (split-side case)
4326 // if the light origin is offscreen on two axes the result will be
4327 // exactly 4 planes (stretched corner case)
4328 for (i = 0;i < 4;i++)
4330 // quickly reject standard frustum planes that put the light
4331 // origin outside the frustum
4332 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4335 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4337 // if all the standard frustum planes were accepted, the light is onscreen
4338 // otherwise we need to generate some more planes below...
4339 if (rtlight->cached_numfrustumplanes < 4)
4341 // at least one of the stock frustum planes failed, so we need to
4342 // create one or two custom planes to enclose the light origin
4343 for (i = 0;i < 4;i++)
4345 // create a plane using the view origin and light origin, and a
4346 // single point from the frustum corner set
4347 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
4348 VectorNormalize(plane.normal);
4349 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
4350 // see if this plane is backwards and flip it if so
4351 for (j = 0;j < 4;j++)
4352 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4356 VectorNegate(plane.normal, plane.normal);
4358 // flipped plane, test again to see if it is now valid
4359 for (j = 0;j < 4;j++)
4360 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4362 // if the plane is still not valid, then it is dividing the
4363 // frustum and has to be rejected
4367 // we have created a valid plane, compute extra info
4368 PlaneClassify(&plane);
4370 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4372 // if we've found 5 frustum planes then we have constructed a
4373 // proper split-side case and do not need to keep searching for
4374 // planes to enclose the light origin
4375 if (rtlight->cached_numfrustumplanes == 5)
4383 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
4385 plane = rtlight->cached_frustumplanes[i];
4386 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));
4391 // now add the light-space box planes if the light box is rotated, as any
4392 // caster outside the oriented light box is irrelevant (even if it passed
4393 // the worldspace light box, which is axial)
4394 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
4396 for (i = 0;i < 6;i++)
4400 v[i >> 1] = (i & 1) ? -1 : 1;
4401 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
4402 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
4403 plane.dist = VectorNormalizeLength(plane.normal);
4404 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
4405 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4411 // add the world-space reduced box planes
4412 for (i = 0;i < 6;i++)
4414 VectorClear(plane.normal);
4415 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
4416 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
4417 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4426 // reduce all plane distances to tightly fit the rtlight cull box, which
4428 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4429 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4430 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4431 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4432 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4433 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4434 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4435 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4436 oldnum = rtlight->cached_numfrustumplanes;
4437 rtlight->cached_numfrustumplanes = 0;
4438 for (j = 0;j < oldnum;j++)
4440 // find the nearest point on the box to this plane
4441 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
4442 for (i = 1;i < 8;i++)
4444 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
4445 if (bestdist > dist)
4448 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);
4449 // if the nearest point is near or behind the plane, we want this
4450 // plane, otherwise the plane is useless as it won't cull anything
4451 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
4453 PlaneClassify(&rtlight->cached_frustumplanes[j]);
4454 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
4461 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
4465 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4467 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4470 GL_CullFace(GL_NONE);
4471 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
4472 for (;mesh;mesh = mesh->next)
4474 if (!mesh->sidetotals[r_shadow_shadowmapside])
4476 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
4477 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4478 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);
4482 else if (r_refdef.scene.worldentity->model)
4483 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);
4485 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4488 static void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
4490 qboolean zpass = false;
4493 int surfacelistindex;
4494 msurface_t *surface;
4496 // if triangle neighbors are disabled, shadowvolumes are disabled
4497 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
4500 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4502 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4505 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
4507 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
4508 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
4510 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
4511 for (;mesh;mesh = mesh->next)
4513 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->numtriangles;
4514 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4515 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
4517 // increment stencil if frontface is infront of depthbuffer
4518 GL_CullFace(r_refdef.view.cullface_back);
4519 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
4520 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);
4521 // decrement stencil if backface is infront of depthbuffer
4522 GL_CullFace(r_refdef.view.cullface_front);
4523 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
4525 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
4527 // decrement stencil if backface is behind depthbuffer
4528 GL_CullFace(r_refdef.view.cullface_front);
4529 R_SetStencil(true, 255, GL_KEEP, GL_DECR, 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);
4531 // increment stencil if frontface is behind depthbuffer
4532 GL_CullFace(r_refdef.view.cullface_back);
4533 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
4535 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);
4539 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
4541 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
4542 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
4543 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
4545 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
4546 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
4547 if (CHECKPVSBIT(trispvs, t))
4548 shadowmarklist[numshadowmark++] = t;
4550 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);
4552 else if (numsurfaces)
4554 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);
4557 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4560 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
4562 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
4563 vec_t relativeshadowradius;
4564 RSurf_ActiveModelEntity(ent, false, false, false);
4565 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
4566 // we need to re-init the shader for each entity because the matrix changed
4567 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
4568 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
4569 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
4570 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
4571 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
4572 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
4573 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
4574 switch (r_shadow_rendermode)
4576 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
4577 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4580 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4583 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4586 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
4588 // set up properties for rendering light onto this entity
4589 RSurf_ActiveModelEntity(ent, true, true, false);
4590 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
4591 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4592 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4593 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4596 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
4598 if (!r_refdef.scene.worldmodel->DrawLight)
4601 // set up properties for rendering light onto this entity
4602 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4603 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
4604 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4605 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4606 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4608 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
4610 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4613 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
4615 dp_model_t *model = ent->model;
4616 if (!model->DrawLight)
4619 R_Shadow_SetupEntityLight(ent);
4621 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
4623 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4626 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
4630 int numleafs, numsurfaces;
4631 int *leaflist, *surfacelist;
4632 unsigned char *leafpvs;
4633 unsigned char *shadowtrispvs;
4634 unsigned char *lighttrispvs;
4635 //unsigned char *surfacesides;
4636 int numlightentities;
4637 int numlightentities_noselfshadow;
4638 int numshadowentities;
4639 int numshadowentities_noselfshadow;
4640 // FIXME: bounds check lightentities and shadowentities, etc.
4641 static entity_render_t *lightentities[MAX_EDICTS];
4642 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
4643 static entity_render_t *shadowentities[MAX_EDICTS];
4644 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
4646 qboolean castshadows;
4648 rtlight->draw = false;
4649 rtlight->cached_numlightentities = 0;
4650 rtlight->cached_numlightentities_noselfshadow = 0;
4651 rtlight->cached_numshadowentities = 0;
4652 rtlight->cached_numshadowentities_noselfshadow = 0;
4653 rtlight->cached_numsurfaces = 0;
4654 rtlight->cached_lightentities = NULL;
4655 rtlight->cached_lightentities_noselfshadow = NULL;
4656 rtlight->cached_shadowentities = NULL;
4657 rtlight->cached_shadowentities_noselfshadow = NULL;
4658 rtlight->cached_shadowtrispvs = NULL;
4659 rtlight->cached_lighttrispvs = NULL;
4660 rtlight->cached_surfacelist = NULL;
4661 rtlight->shadowmapsidesize = 0;
4663 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
4664 // skip lights that are basically invisible (color 0 0 0)
4665 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
4667 // loading is done before visibility checks because loading should happen
4668 // all at once at the start of a level, not when it stalls gameplay.
4669 // (especially important to benchmarks)
4671 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
4673 if (rtlight->compiled)
4674 R_RTLight_Uncompile(rtlight);
4675 R_RTLight_Compile(rtlight);
4679 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
4681 // look up the light style value at this time
4682 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4683 VectorScale(rtlight->color, f, rtlight->currentcolor);
4685 if (rtlight->selected)
4687 f = 2 + sin(realtime * M_PI * 4.0);
4688 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
4692 // skip if lightstyle is currently off
4693 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
4696 // skip processing on corona-only lights
4700 // skip if the light box is not touching any visible leafs
4701 if (r_shadow_culllights_pvs.integer
4702 && r_refdef.scene.worldmodel
4703 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
4704 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, rtlight->cullmins, rtlight->cullmaxs))
4707 // skip if the light box is not visible to traceline
4708 if (r_shadow_culllights_trace.integer)
4710 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))
4711 rtlight->trace_timer = realtime;
4712 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
4716 // skip if the light box is off screen
4717 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
4720 // in the typical case this will be quickly replaced by GetLightInfo
4721 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
4722 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
4724 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4726 // 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
4727 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
4730 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
4732 // compiled light, world available and can receive realtime lighting
4733 // retrieve leaf information
4734 numleafs = rtlight->static_numleafs;
4735 leaflist = rtlight->static_leaflist;
4736 leafpvs = rtlight->static_leafpvs;
4737 numsurfaces = rtlight->static_numsurfaces;
4738 surfacelist = rtlight->static_surfacelist;
4739 //surfacesides = NULL;
4740 shadowtrispvs = rtlight->static_shadowtrispvs;
4741 lighttrispvs = rtlight->static_lighttrispvs;
4743 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4745 // dynamic light, world available and can receive realtime lighting
4746 // calculate lit surfaces and leafs
4747 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);
4748 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4749 leaflist = r_shadow_buffer_leaflist;
4750 leafpvs = r_shadow_buffer_leafpvs;
4751 surfacelist = r_shadow_buffer_surfacelist;
4752 //surfacesides = r_shadow_buffer_surfacesides;
4753 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4754 lighttrispvs = r_shadow_buffer_lighttrispvs;
4755 // if the reduced leaf bounds are offscreen, skip it
4756 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4767 //surfacesides = NULL;
4768 shadowtrispvs = NULL;
4769 lighttrispvs = NULL;
4771 // check if light is illuminating any visible leafs
4774 for (i = 0; i < numleafs; i++)
4775 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4781 // make a list of lit entities and shadow casting entities
4782 numlightentities = 0;
4783 numlightentities_noselfshadow = 0;
4784 numshadowentities = 0;
4785 numshadowentities_noselfshadow = 0;
4787 // add dynamic entities that are lit by the light
4788 for (i = 0; i < r_refdef.scene.numentities; i++)
4791 entity_render_t *ent = r_refdef.scene.entities[i];
4793 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4795 // skip the object entirely if it is not within the valid
4796 // shadow-casting region (which includes the lit region)
4797 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
4799 if (!(model = ent->model))
4801 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4803 // this entity wants to receive light, is visible, and is
4804 // inside the light box
4805 // TODO: check if the surfaces in the model can receive light
4806 // so now check if it's in a leaf seen by the light
4807 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))
4809 if (ent->flags & RENDER_NOSELFSHADOW)
4810 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
4812 lightentities[numlightentities++] = ent;
4813 // since it is lit, it probably also casts a shadow...
4814 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4815 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4816 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4818 // note: exterior models without the RENDER_NOSELFSHADOW
4819 // flag still create a RENDER_NOSELFSHADOW shadow but
4820 // are lit normally, this means that they are
4821 // self-shadowing but do not shadow other
4822 // RENDER_NOSELFSHADOW entities such as the gun
4823 // (very weird, but keeps the player shadow off the gun)
4824 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4825 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4827 shadowentities[numshadowentities++] = ent;
4830 else if (ent->flags & RENDER_SHADOW)
4832 // this entity is not receiving light, but may still need to
4834 // TODO: check if the surfaces in the model can cast shadow
4835 // now check if it is in a leaf seen by the light
4836 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))
4838 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4839 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4840 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4842 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4843 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4845 shadowentities[numshadowentities++] = ent;
4850 // return if there's nothing at all to light
4851 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4854 // count this light in the r_speeds
4855 r_refdef.stats[r_stat_lights]++;
4857 // flag it as worth drawing later
4858 rtlight->draw = true;
4860 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
4861 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4863 numshadowentities = numshadowentities_noselfshadow = 0;
4864 rtlight->castshadows = castshadows;
4866 // cache all the animated entities that cast a shadow but are not visible
4867 for (i = 0; i < numshadowentities; i++)
4868 R_AnimCache_GetEntity(shadowentities[i], false, false);
4869 for (i = 0; i < numshadowentities_noselfshadow; i++)
4870 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4872 // 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)
4873 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
4875 for (i = 0; i < numshadowentities_noselfshadow; i++)
4876 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
4877 numshadowentities_noselfshadow = 0;
4880 // we can convert noselfshadow to regular if there are no casters of that type
4881 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
4883 for (i = 0; i < numlightentities_noselfshadow; i++)
4884 lightentities[numlightentities++] = lightentities_noselfshadow[i];
4885 numlightentities_noselfshadow = 0;
4888 // allocate some temporary memory for rendering this light later in the frame
4889 // reusable buffers need to be copied, static data can be used as-is
4890 rtlight->cached_numlightentities = numlightentities;
4891 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
4892 rtlight->cached_numshadowentities = numshadowentities;
4893 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4894 rtlight->cached_numsurfaces = numsurfaces;
4895 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4896 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4897 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4898 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4899 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4901 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4902 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4903 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4904 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4905 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4909 // compiled light data
4910 rtlight->cached_shadowtrispvs = shadowtrispvs;
4911 rtlight->cached_lighttrispvs = lighttrispvs;
4912 rtlight->cached_surfacelist = surfacelist;
4915 if (R_Shadow_ShadowMappingEnabled())
4917 // figure out the shadowmapping parameters for this light
4918 vec3_t nearestpoint;
4921 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4922 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4923 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4924 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4925 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
4926 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4927 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4928 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4929 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
4933 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
4937 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4938 int numlightentities;
4939 int numlightentities_noselfshadow;
4940 int numshadowentities;
4941 int numshadowentities_noselfshadow;
4942 entity_render_t **lightentities;
4943 entity_render_t **lightentities_noselfshadow;
4944 entity_render_t **shadowentities;
4945 entity_render_t **shadowentities_noselfshadow;
4947 static unsigned char entitysides[MAX_EDICTS];
4948 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4954 matrix4x4_t radiustolight;
4956 // check if we cached this light this frame (meaning it is worth drawing)
4957 if (!rtlight->draw || !rtlight->castshadows)
4960 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
4961 if (rtlight->shadowmapatlassidesize == 0)
4963 rtlight->castshadows = false;
4967 // set up a scissor rectangle for this light
4968 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4971 // don't let sound skip if going slow
4972 if (r_refdef.scene.extraupdate)
4975 numlightentities = rtlight->cached_numlightentities;
4976 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4977 numshadowentities = rtlight->cached_numshadowentities;
4978 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4979 numsurfaces = rtlight->cached_numsurfaces;
4980 lightentities = rtlight->cached_lightentities;
4981 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4982 shadowentities = rtlight->cached_shadowentities;
4983 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4984 shadowtrispvs = rtlight->cached_shadowtrispvs;
4985 lighttrispvs = rtlight->cached_lighttrispvs;
4986 surfacelist = rtlight->cached_surfacelist;
4988 // make this the active rtlight for rendering purposes
4989 R_Shadow_RenderMode_ActiveLight(rtlight);
4991 radiustolight = rtlight->matrix_worldtolight;
4992 Matrix4x4_Abs(&radiustolight);
4994 size = rtlight->shadowmapatlassidesize;
4995 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4997 surfacesides = NULL;
5002 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
5004 castermask = rtlight->static_shadowmap_casters;
5005 receivermask = rtlight->static_shadowmap_receivers;
5009 surfacesides = r_shadow_buffer_surfacesides;
5010 for (i = 0; i < numsurfaces; i++)
5012 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
5013 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
5014 castermask |= surfacesides[i];
5015 receivermask |= surfacesides[i];
5020 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
5021 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
5022 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
5023 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
5025 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
5029 for (i = 0; i < numshadowentities; i++)
5030 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
5031 for (i = 0; i < numshadowentities_noselfshadow; i++)
5032 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
5035 // there is no need to render shadows for sides that have no receivers...
5036 castermask &= receivermask;
5038 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
5040 // render shadow casters into shadowmaps for this light
5041 for (side = 0; side < 6; side++)
5043 int bit = 1 << side;
5044 if (castermask & bit)
5046 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
5048 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
5049 for (i = 0; i < numshadowentities; i++)
5050 if (entitysides[i] & bit)
5051 R_Shadow_DrawEntityShadow(shadowentities[i]);
5052 for (i = 0; i < numshadowentities_noselfshadow; i++)
5053 if (entitysides_noselfshadow[i] & bit)
5054 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5057 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
5058 if (numshadowentities_noselfshadow)
5060 for (side = 0; side < 6; side++)
5062 int bit = 1 << side;
5063 if (castermask & bit)
5065 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
5067 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
5068 for (i = 0; i < numshadowentities; i++)
5069 if (entitysides[i] & bit)
5070 R_Shadow_DrawEntityShadow(shadowentities[i]);
5076 static void R_Shadow_DrawLight(rtlight_t *rtlight)
5080 unsigned char *shadowtrispvs, *lighttrispvs;
5081 int numlightentities;
5082 int numlightentities_noselfshadow;
5083 int numshadowentities;
5084 int numshadowentities_noselfshadow;
5085 entity_render_t **lightentities;
5086 entity_render_t **lightentities_noselfshadow;
5087 entity_render_t **shadowentities;
5088 entity_render_t **shadowentities_noselfshadow;
5090 qboolean castshadows;
5092 // check if we cached this light this frame (meaning it is worth drawing)
5096 // set up a scissor rectangle for this light
5097 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
5100 // don't let sound skip if going slow
5101 if (r_refdef.scene.extraupdate)
5104 numlightentities = rtlight->cached_numlightentities;
5105 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
5106 numshadowentities = rtlight->cached_numshadowentities;
5107 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
5108 numsurfaces = rtlight->cached_numsurfaces;
5109 lightentities = rtlight->cached_lightentities;
5110 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
5111 shadowentities = rtlight->cached_shadowentities;
5112 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
5113 shadowtrispvs = rtlight->cached_shadowtrispvs;
5114 lighttrispvs = rtlight->cached_lighttrispvs;
5115 surfacelist = rtlight->cached_surfacelist;
5116 castshadows = rtlight->castshadows;
5118 // make this the active rtlight for rendering purposes
5119 R_Shadow_RenderMode_ActiveLight(rtlight);
5121 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
5123 // optionally draw visible shape of the shadow volumes
5124 // for performance analysis by level designers
5125 R_Shadow_RenderMode_VisibleShadowVolumes();
5127 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
5128 for (i = 0;i < numshadowentities;i++)
5129 R_Shadow_DrawEntityShadow(shadowentities[i]);
5130 for (i = 0;i < numshadowentities_noselfshadow;i++)
5131 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5132 R_Shadow_RenderMode_VisibleLighting(false, false);
5135 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
5137 // optionally draw the illuminated areas
5138 // for performance analysis by level designers
5139 R_Shadow_RenderMode_VisibleLighting(false, false);
5141 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5142 for (i = 0;i < numlightentities;i++)
5143 R_Shadow_DrawEntityLight(lightentities[i]);
5144 for (i = 0;i < numlightentities_noselfshadow;i++)
5145 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5148 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
5152 float shadowmapoffsetnoselfshadow = 0;
5153 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
5154 Matrix4x4_Abs(&radiustolight);
5156 size = rtlight->shadowmapatlassidesize;
5157 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
5159 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
5161 if (rtlight->cached_numshadowentities_noselfshadow)
5162 shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
5164 // render lighting using the depth texture as shadowmap
5165 // draw lighting in the unmasked areas
5166 if (numsurfaces + numlightentities)
5168 R_Shadow_RenderMode_Lighting(false, false, true, false);
5169 // draw lighting in the unmasked areas
5171 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5172 for (i = 0; i < numlightentities; i++)
5173 R_Shadow_DrawEntityLight(lightentities[i]);
5175 // offset to the noselfshadow part of the atlas and draw those too
5176 if (numlightentities_noselfshadow)
5178 R_Shadow_RenderMode_Lighting(false, false, true, true);
5179 for (i = 0; i < numlightentities_noselfshadow; i++)
5180 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5183 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5184 if (r_shadow_usingdeferredprepass)
5185 R_Shadow_RenderMode_DrawDeferredLight(true);
5187 else if (castshadows && vid.stencil)
5189 // draw stencil shadow volumes to mask off pixels that are in shadow
5190 // so that they won't receive lighting
5191 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
5192 R_Shadow_ClearStencil();
5195 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
5196 for (i = 0;i < numshadowentities;i++)
5197 R_Shadow_DrawEntityShadow(shadowentities[i]);
5199 // draw lighting in the unmasked areas
5200 R_Shadow_RenderMode_Lighting(true, false, false, false);
5201 for (i = 0;i < numlightentities_noselfshadow;i++)
5202 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5204 for (i = 0;i < numshadowentities_noselfshadow;i++)
5205 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5207 // draw lighting in the unmasked areas
5208 R_Shadow_RenderMode_Lighting(true, false, false, false);
5210 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5211 for (i = 0;i < numlightentities;i++)
5212 R_Shadow_DrawEntityLight(lightentities[i]);
5214 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5215 if (r_shadow_usingdeferredprepass)
5216 R_Shadow_RenderMode_DrawDeferredLight(false);
5220 // draw lighting in the unmasked areas
5221 R_Shadow_RenderMode_Lighting(false, false, false, false);
5223 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5224 for (i = 0;i < numlightentities;i++)
5225 R_Shadow_DrawEntityLight(lightentities[i]);
5226 for (i = 0;i < numlightentities_noselfshadow;i++)
5227 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5229 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5230 if (r_shadow_usingdeferredprepass)
5231 R_Shadow_RenderMode_DrawDeferredLight(false);
5235 static void R_Shadow_FreeDeferred(void)
5237 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
5238 r_shadow_prepassgeometryfbo = 0;
5240 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
5241 r_shadow_prepasslightingdiffusespecularfbo = 0;
5243 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
5244 r_shadow_prepasslightingdiffusefbo = 0;
5246 if (r_shadow_prepassgeometrydepthbuffer)
5247 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
5248 r_shadow_prepassgeometrydepthbuffer = NULL;
5250 if (r_shadow_prepassgeometrynormalmaptexture)
5251 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
5252 r_shadow_prepassgeometrynormalmaptexture = NULL;
5254 if (r_shadow_prepasslightingdiffusetexture)
5255 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
5256 r_shadow_prepasslightingdiffusetexture = NULL;
5258 if (r_shadow_prepasslightingspeculartexture)
5259 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
5260 r_shadow_prepasslightingspeculartexture = NULL;
5263 void R_Shadow_DrawPrepass(void)
5267 entity_render_t *ent;
5268 float clearcolor[4];
5270 R_Mesh_ResetTextureState();
5272 GL_ColorMask(1,1,1,1);
5273 GL_BlendFunc(GL_ONE, GL_ZERO);
5276 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5277 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
5278 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
5279 if (r_timereport_active)
5280 R_TimeReport("prepasscleargeom");
5282 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
5283 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
5284 if (r_timereport_active)
5285 R_TimeReport("prepassworld");
5287 for (i = 0;i < r_refdef.scene.numentities;i++)
5289 if (!r_refdef.viewcache.entityvisible[i])
5291 ent = r_refdef.scene.entities[i];
5292 if (ent->model && ent->model->DrawPrepass != NULL)
5293 ent->model->DrawPrepass(ent);
5296 if (r_timereport_active)
5297 R_TimeReport("prepassmodels");
5299 GL_DepthMask(false);
5300 GL_ColorMask(1,1,1,1);
5303 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5304 Vector4Set(clearcolor, 0, 0, 0, 0);
5305 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
5306 if (r_timereport_active)
5307 R_TimeReport("prepassclearlit");
5309 R_Shadow_RenderMode_Begin();
5311 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5312 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5314 R_Shadow_RenderMode_End();
5316 if (r_timereport_active)
5317 R_TimeReport("prepasslights");
5320 #define MAX_SCENELIGHTS 65536
5321 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
5323 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
5325 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
5327 r_shadow_scenemaxlights *= 2;
5328 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
5329 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
5331 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
5335 void R_Shadow_DrawLightSprites(void);
5336 void R_Shadow_PrepareLights(void)
5345 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
5346 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
5347 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
5349 if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
5350 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
5351 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
5352 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
5353 r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) ||
5354 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
5355 r_shadow_shadowmapborder != shadowmapborder ||
5356 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
5357 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
5358 R_Shadow_FreeShadowMaps();
5360 r_shadow_usingshadowmaportho = false;
5362 switch (vid.renderpath)
5364 case RENDERPATH_GL20:
5365 case RENDERPATH_D3D9:
5366 case RENDERPATH_D3D10:
5367 case RENDERPATH_D3D11:
5368 case RENDERPATH_SOFT:
5370 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
5372 r_shadow_usingdeferredprepass = false;
5373 if (r_shadow_prepass_width)
5374 R_Shadow_FreeDeferred();
5375 r_shadow_prepass_width = r_shadow_prepass_height = 0;
5379 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
5381 R_Shadow_FreeDeferred();
5383 r_shadow_usingdeferredprepass = true;
5384 r_shadow_prepass_width = vid.width;
5385 r_shadow_prepass_height = vid.height;
5386 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
5387 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);
5388 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);
5389 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);
5391 // set up the geometry pass fbo (depth + normalmap)
5392 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5393 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5394 // render depth into a renderbuffer and other important properties into the normalmap texture
5396 // set up the lighting pass fbo (diffuse + specular)
5397 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5398 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5399 // render diffuse into one texture and specular into another,
5400 // with depth and normalmap bound as textures,
5401 // with depth bound as attachment as well
5403 // set up the lighting pass fbo (diffuse)
5404 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5405 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5406 // render diffuse into one texture,
5407 // with depth and normalmap bound as textures,
5408 // with depth bound as attachment as well
5412 case RENDERPATH_GL11:
5413 case RENDERPATH_GL13:
5414 case RENDERPATH_GLES1:
5415 case RENDERPATH_GLES2:
5416 r_shadow_usingdeferredprepass = false;
5420 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);
5422 r_shadow_scenenumlights = 0;
5423 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5424 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5425 for (lightindex = 0; lightindex < range; lightindex++)
5427 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5428 if (light && (light->flags & flag))
5430 R_Shadow_PrepareLight(&light->rtlight);
5431 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5434 if (r_refdef.scene.rtdlight)
5436 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5438 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
5439 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
5442 else if (gl_flashblend.integer)
5444 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5446 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
5447 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
5448 VectorScale(rtlight->color, f, rtlight->currentcolor);
5452 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
5453 if (r_shadow_debuglight.integer >= 0)
5455 r_shadow_scenenumlights = 0;
5456 lightindex = r_shadow_debuglight.integer;
5457 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5460 R_Shadow_PrepareLight(&light->rtlight);
5461 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5465 // if we're doing shadowmaps we need to prepare the atlas layout now
5466 if (R_Shadow_ShadowMappingEnabled())
5470 // allocate shadowmaps in the atlas now
5471 // 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...
5472 for (lod = 0; lod < 16; lod++)
5474 int packing_success = 0;
5475 int packing_failure = 0;
5476 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
5477 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
5478 if (r_shadow_shadowmapatlas_modelshadows_size)
5479 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);
5480 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5482 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
5483 int size = rtlight->shadowmapsidesize >> lod;
5485 if (!rtlight->castshadows)
5487 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
5490 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
5491 if (rtlight->cached_numshadowentities_noselfshadow)
5493 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
5495 rtlight->shadowmapatlassidesize = size;
5500 // note down that we failed to pack this one, it will have to disable shadows
5501 rtlight->shadowmapatlassidesize = 0;
5505 // generally everything fits and we stop here on the first iteration
5506 if (packing_failure == 0)
5511 if (r_editlights.integer)
5512 R_Shadow_DrawLightSprites();
5515 void R_Shadow_DrawShadowMaps(void)
5517 R_Shadow_RenderMode_Begin();
5518 R_Shadow_RenderMode_ActiveLight(NULL);
5520 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
5521 R_Shadow_ClearShadowMapTexture();
5523 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
5524 if (r_shadow_shadowmapatlas_modelshadows_size)
5526 R_Shadow_DrawModelShadowMaps();
5527 // don't let sound skip if going slow
5528 if (r_refdef.scene.extraupdate)
5532 if (R_Shadow_ShadowMappingEnabled())
5535 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5536 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
5539 R_Shadow_RenderMode_End();
5542 void R_Shadow_DrawLights(void)
5546 R_Shadow_RenderMode_Begin();
5548 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5549 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5551 R_Shadow_RenderMode_End();
5554 #define MAX_MODELSHADOWS 1024
5555 static int r_shadow_nummodelshadows;
5556 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
5558 void R_Shadow_PrepareModelShadows(void)
5561 float scale, size, radius, dot1, dot2;
5562 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5563 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
5564 entity_render_t *ent;
5566 r_shadow_nummodelshadows = 0;
5567 r_shadow_shadowmapatlas_modelshadows_size = 0;
5569 if (!r_refdef.scene.numentities || r_refdef.scene.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
5572 switch (r_shadow_shadowmode)
5574 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
5575 if (r_shadows.integer >= 2)
5578 case R_SHADOW_SHADOWMODE_STENCIL:
5581 for (i = 0; i < r_refdef.scene.numentities; i++)
5583 ent = r_refdef.scene.entities[i];
5584 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5586 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5588 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5589 R_AnimCache_GetEntity(ent, false, false);
5597 size = r_shadow_shadowmaptexturesize / 4;
5598 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
5599 radius = 0.5f * size / scale;
5601 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5602 VectorCopy(prvmshadowdir, shadowdir);
5603 VectorNormalize(shadowdir);
5604 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5605 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5606 if (fabs(dot1) <= fabs(dot2))
5607 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5609 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5610 VectorNormalize(shadowforward);
5611 CrossProduct(shadowdir, shadowforward, shadowright);
5612 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5613 VectorCopy(prvmshadowfocus, shadowfocus);
5614 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5615 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5616 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5617 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5618 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5620 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5622 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5623 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5624 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5625 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5626 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5627 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5629 for (i = 0; i < r_refdef.scene.numentities; i++)
5631 ent = r_refdef.scene.entities[i];
5632 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
5634 // cast shadows from anything of the map (submodels are optional)
5635 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5637 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5639 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5640 R_AnimCache_GetEntity(ent, false, false);
5644 if (r_shadow_nummodelshadows)
5646 r_shadow_shadowmapatlas_modelshadows_x = 0;
5647 r_shadow_shadowmapatlas_modelshadows_y = 0;
5648 r_shadow_shadowmapatlas_modelshadows_size = size;
5652 static void R_Shadow_DrawModelShadowMaps(void)
5655 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
5656 entity_render_t *ent;
5657 vec3_t relativelightorigin;
5658 vec3_t relativelightdirection, relativeforward, relativeright;
5659 vec3_t relativeshadowmins, relativeshadowmaxs;
5660 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
5661 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5663 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
5664 r_viewport_t viewport;
5666 size = r_shadow_shadowmapatlas_modelshadows_size;
5667 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
5668 radius = 0.5f / scale;
5669 nearclip = -r_shadows_throwdistance.value;
5670 farclip = r_shadows_throwdistance.value;
5671 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);
5673 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
5674 r_shadow_modelshadowmap_parameters[0] = size;
5675 r_shadow_modelshadowmap_parameters[1] = size;
5676 r_shadow_modelshadowmap_parameters[2] = 1.0;
5677 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
5678 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
5679 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
5680 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
5681 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
5682 r_shadow_usingshadowmaportho = true;
5684 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5685 VectorCopy(prvmshadowdir, shadowdir);
5686 VectorNormalize(shadowdir);
5687 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5688 VectorCopy(prvmshadowfocus, shadowfocus);
5689 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5690 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5691 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5692 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5693 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5694 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5695 if (fabs(dot1) <= fabs(dot2))
5696 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5698 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5699 VectorNormalize(shadowforward);
5700 VectorM(scale, shadowforward, &m[0]);
5701 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5703 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
5704 CrossProduct(shadowdir, shadowforward, shadowright);
5705 VectorM(scale, shadowright, &m[4]);
5706 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
5707 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
5708 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
5709 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
5710 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
5711 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);
5712 R_SetViewport(&viewport);
5714 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5716 // render into a slightly restricted region so that the borders of the
5717 // shadowmap area fade away, rather than streaking across everything
5718 // outside the usable area
5719 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
5721 for (i = 0;i < r_shadow_nummodelshadows;i++)
5723 ent = r_shadow_modelshadows[i];
5724 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5725 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
5726 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5727 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
5728 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
5729 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5730 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5731 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5732 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5733 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5734 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5735 RSurf_ActiveModelEntity(ent, false, false, false);
5736 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
5737 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5743 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
5745 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
5747 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
5748 Cvar_SetValueQuick(&r_test, 0);
5753 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
5754 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
5755 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
5756 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
5757 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
5758 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
5760 switch (vid.renderpath)
5762 case RENDERPATH_GL11:
5763 case RENDERPATH_GL13:
5764 case RENDERPATH_GL20:
5765 case RENDERPATH_SOFT:
5766 case RENDERPATH_GLES1:
5767 case RENDERPATH_GLES2:
5769 case RENDERPATH_D3D9:
5770 case RENDERPATH_D3D10:
5771 case RENDERPATH_D3D11:
5772 #ifdef MATRIX4x4_OPENGLORIENTATION
5773 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5774 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
5775 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
5776 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
5778 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5779 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
5780 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
5781 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
5787 void R_Shadow_DrawModelShadows(void)
5790 float relativethrowdistance;
5791 entity_render_t *ent;
5792 vec3_t relativelightorigin;
5793 vec3_t relativelightdirection;
5794 vec3_t relativeshadowmins, relativeshadowmaxs;
5795 vec3_t tmp, shadowdir;
5796 prvm_vec3_t prvmshadowdir;
5798 if (!r_shadow_nummodelshadows || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
5801 R_ResetViewRendering3D(r_shadow_viewfbo, r_shadow_viewdepthtexture, r_shadow_viewcolortexture, r_shadow_viewx, r_shadow_viewy, r_shadow_viewwidth, r_shadow_viewheight);
5802 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
5803 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5804 R_Shadow_RenderMode_Begin();
5805 R_Shadow_RenderMode_ActiveLight(NULL);
5806 r_shadow_lightscissor[0] = r_shadow_viewx;
5807 r_shadow_lightscissor[1] = (r_shadow_viewfbo ? r_shadow_viewheight : vid.height) - r_shadow_viewy - r_shadow_viewheight;
5808 r_shadow_lightscissor[2] = r_shadow_viewwidth;
5809 r_shadow_lightscissor[3] = r_shadow_viewheight;
5810 R_Shadow_RenderMode_StencilShadowVolumes(false);
5813 if (r_shadows.integer == 2)
5815 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5816 VectorCopy(prvmshadowdir, shadowdir);
5817 VectorNormalize(shadowdir);
5820 R_Shadow_ClearStencil();
5822 for (i = 0;i < r_shadow_nummodelshadows;i++)
5824 ent = r_shadow_modelshadows[i];
5826 // cast shadows from anything of the map (submodels are optional)
5827 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5828 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
5829 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
5830 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
5831 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5834 VectorNegate(ent->render_modellight_lightdir, tmp);
5835 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
5838 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
5839 RSurf_ActiveModelEntity(ent, false, false, false);
5840 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
5841 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5844 // not really the right mode, but this will disable any silly stencil features
5845 R_Shadow_RenderMode_End();
5847 // set up ortho view for rendering this pass
5848 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5849 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5850 //GL_ScissorTest(true);
5851 //R_EntityMatrix(&identitymatrix);
5852 //R_Mesh_ResetTextureState();
5853 R_ResetViewRendering2D(r_shadow_viewfbo, r_shadow_viewdepthtexture, r_shadow_viewcolortexture, r_shadow_viewx, r_shadow_viewy, r_shadow_viewwidth, r_shadow_viewheight);
5855 // set up a darkening blend on shadowed areas
5856 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5857 //GL_DepthRange(0, 1);
5858 //GL_DepthTest(false);
5859 //GL_DepthMask(false);
5860 //GL_PolygonOffset(0, 0);CHECKGLERROR
5861 GL_Color(0, 0, 0, r_shadows_darken.value);
5862 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5863 //GL_DepthFunc(GL_ALWAYS);
5864 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5866 // apply the blend to the shadowed areas
5867 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5868 R_SetupShader_Generic_NoTexture(false, true);
5869 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5871 // restore the viewport
5872 R_SetViewport(&r_refdef.view.viewport);
5874 // restore other state to normal
5875 //R_Shadow_RenderMode_End();
5878 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5881 vec3_t centerorigin;
5882 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5885 // if it's too close, skip it
5886 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5888 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5891 if (usequery && r_numqueries + 2 <= r_maxqueries)
5893 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5894 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5895 // 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
5896 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5898 switch(vid.renderpath)
5900 case RENDERPATH_GL11:
5901 case RENDERPATH_GL13:
5902 case RENDERPATH_GL20:
5903 case RENDERPATH_GLES1:
5904 case RENDERPATH_GLES2:
5905 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5907 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5908 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5909 GL_DepthFunc(GL_ALWAYS);
5910 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5911 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5912 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5913 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5914 GL_DepthFunc(GL_LEQUAL);
5915 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5916 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5917 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5918 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5919 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5923 case RENDERPATH_D3D9:
5924 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5926 case RENDERPATH_D3D10:
5927 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5929 case RENDERPATH_D3D11:
5930 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5932 case RENDERPATH_SOFT:
5933 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5937 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5940 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5942 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5945 unsigned int occlude = 0;
5946 GLint allpixels = 0, visiblepixels = 0;
5948 // now we have to check the query result
5949 if (rtlight->corona_queryindex_visiblepixels)
5951 switch(vid.renderpath)
5953 case RENDERPATH_GL20:
5954 case RENDERPATH_GLES1:
5955 case RENDERPATH_GLES2:
5956 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5957 // See if we can use the GPU-side method to prevent implicit sync
5958 if (vid.support.arb_query_buffer_object) {
5959 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
5960 if (!r_shadow_occlusion_buf) {
5961 qglGenBuffersARB(1, &r_shadow_occlusion_buf);
5962 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5963 qglBufferDataARB(GL_QUERY_BUFFER_ARB, 8, NULL, GL_DYNAMIC_COPY);
5965 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5967 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(0));
5968 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4));
5969 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
5970 occlude = MATERIALFLAG_OCCLUDE;
5971 cscale *= rtlight->corona_visibility;
5979 case RENDERPATH_GL11:
5980 case RENDERPATH_GL13:
5981 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5983 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5984 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5985 if (visiblepixels < 1 || allpixels < 1)
5987 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5988 cscale *= rtlight->corona_visibility;
5994 case RENDERPATH_D3D9:
5995 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5997 case RENDERPATH_D3D10:
5998 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6000 case RENDERPATH_D3D11:
6001 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6003 case RENDERPATH_SOFT:
6004 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6012 if (CL_Cache_TraceLineSurfaces(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT).fraction < 1)
6015 VectorScale(rtlight->currentcolor, cscale, color);
6016 if (VectorLength(color) > (1.0f / 256.0f))
6019 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
6022 VectorNegate(color, color);
6023 GL_BlendEquationSubtract(true);
6025 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
6026 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);
6027 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
6029 GL_BlendEquationSubtract(false);
6033 void R_Shadow_DrawCoronas(void)
6036 qboolean usequery = false;
6041 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
6043 if (r_fb.water.renderingscene)
6045 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6046 R_EntityMatrix(&identitymatrix);
6048 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6050 // check occlusion of coronas
6051 // use GL_ARB_occlusion_query if available
6052 // otherwise use raytraces
6054 switch (vid.renderpath)
6056 case RENDERPATH_GL11:
6057 case RENDERPATH_GL13:
6058 case RENDERPATH_GL20:
6059 case RENDERPATH_GLES1:
6060 case RENDERPATH_GLES2:
6061 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
6062 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
6065 GL_ColorMask(0,0,0,0);
6066 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
6067 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
6070 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
6071 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
6073 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
6076 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6077 GL_BlendFunc(GL_ONE, GL_ZERO);
6078 GL_CullFace(GL_NONE);
6079 GL_DepthMask(false);
6080 GL_DepthRange(0, 1);
6081 GL_PolygonOffset(0, 0);
6083 R_Mesh_ResetTextureState();
6084 R_SetupShader_Generic_NoTexture(false, false);
6088 case RENDERPATH_D3D9:
6090 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6092 case RENDERPATH_D3D10:
6093 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6095 case RENDERPATH_D3D11:
6096 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6098 case RENDERPATH_SOFT:
6100 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6103 for (lightindex = 0;lightindex < range;lightindex++)
6105 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6108 rtlight = &light->rtlight;
6109 rtlight->corona_visibility = 0;
6110 rtlight->corona_queryindex_visiblepixels = 0;
6111 rtlight->corona_queryindex_allpixels = 0;
6112 if (!(rtlight->flags & flag))
6114 if (rtlight->corona <= 0)
6116 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
6118 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6120 for (i = 0;i < r_refdef.scene.numlights;i++)
6122 rtlight = r_refdef.scene.lights[i];
6123 rtlight->corona_visibility = 0;
6124 rtlight->corona_queryindex_visiblepixels = 0;
6125 rtlight->corona_queryindex_allpixels = 0;
6126 if (!(rtlight->flags & flag))
6128 if (rtlight->corona <= 0)
6130 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6133 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
6135 // now draw the coronas using the query data for intensity info
6136 for (lightindex = 0;lightindex < range;lightindex++)
6138 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6141 rtlight = &light->rtlight;
6142 if (rtlight->corona_visibility <= 0)
6144 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6146 for (i = 0;i < r_refdef.scene.numlights;i++)
6148 rtlight = r_refdef.scene.lights[i];
6149 if (rtlight->corona_visibility <= 0)
6151 if (gl_flashblend.integer)
6152 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
6154 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6160 static dlight_t *R_Shadow_NewWorldLight(void)
6162 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
6165 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)
6169 // 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
6171 // validate parameters
6175 // copy to light properties
6176 VectorCopy(origin, light->origin);
6177 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
6178 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
6179 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
6181 light->color[0] = max(color[0], 0);
6182 light->color[1] = max(color[1], 0);
6183 light->color[2] = max(color[2], 0);
6185 light->color[0] = color[0];
6186 light->color[1] = color[1];
6187 light->color[2] = color[2];
6188 light->radius = max(radius, 0);
6189 light->style = style;
6190 light->shadow = shadowenable;
6191 light->corona = corona;
6192 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
6193 light->coronasizescale = coronasizescale;
6194 light->ambientscale = ambientscale;
6195 light->diffusescale = diffusescale;
6196 light->specularscale = specularscale;
6197 light->flags = flags;
6199 // update renderable light data
6200 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
6201 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);
6204 static void R_Shadow_FreeWorldLight(dlight_t *light)
6206 if (r_shadow_selectedlight == light)
6207 r_shadow_selectedlight = NULL;
6208 R_RTLight_Uncompile(&light->rtlight);
6209 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
6212 void R_Shadow_ClearWorldLights(void)
6216 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6217 for (lightindex = 0;lightindex < range;lightindex++)
6219 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6221 R_Shadow_FreeWorldLight(light);
6223 r_shadow_selectedlight = NULL;
6226 static void R_Shadow_SelectLight(dlight_t *light)
6228 if (r_shadow_selectedlight)
6229 r_shadow_selectedlight->selected = false;
6230 r_shadow_selectedlight = light;
6231 if (r_shadow_selectedlight)
6232 r_shadow_selectedlight->selected = true;
6235 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6237 // this is never batched (there can be only one)
6239 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
6240 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6241 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6244 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6249 skinframe_t *skinframe;
6252 // this is never batched (due to the ent parameter changing every time)
6253 // so numsurfaces == 1 and surfacelist[0] == lightnumber
6254 const dlight_t *light = (dlight_t *)ent;
6257 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
6260 VectorScale(light->color, intensity, spritecolor);
6261 if (VectorLength(spritecolor) < 0.1732f)
6262 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
6263 if (VectorLength(spritecolor) > 1.0f)
6264 VectorNormalize(spritecolor);
6266 // draw light sprite
6267 if (light->cubemapname[0] && !light->shadow)
6268 skinframe = r_editlights_sprcubemapnoshadowlight;
6269 else if (light->cubemapname[0])
6270 skinframe = r_editlights_sprcubemaplight;
6271 else if (!light->shadow)
6272 skinframe = r_editlights_sprnoshadowlight;
6274 skinframe = r_editlights_sprlight;
6276 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);
6277 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6279 // draw selection sprite if light is selected
6280 if (light->selected)
6282 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6283 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6284 // VorteX todo: add normalmode/realtime mode light overlay sprites?
6288 void R_Shadow_DrawLightSprites(void)
6292 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6293 for (lightindex = 0;lightindex < range;lightindex++)
6295 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6297 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
6299 if (!r_editlights_lockcursor)
6300 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
6303 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
6308 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6309 if (lightindex >= range)
6311 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6314 rtlight = &light->rtlight;
6315 //if (!(rtlight->flags & flag))
6317 VectorCopy(rtlight->shadoworigin, origin);
6318 *radius = rtlight->radius;
6319 VectorCopy(rtlight->color, color);
6323 static void R_Shadow_SelectLightInView(void)
6325 float bestrating, rating, temp[3];
6329 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6333 if (r_editlights_lockcursor)
6335 for (lightindex = 0;lightindex < range;lightindex++)
6337 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6340 VectorSubtract(light->origin, r_refdef.view.origin, temp);
6341 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
6344 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
6345 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1.0f)
6347 bestrating = rating;
6352 R_Shadow_SelectLight(best);
6355 void R_Shadow_LoadWorldLights(void)
6357 int n, a, style, shadow, flags;
6358 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
6359 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
6360 if (cl.worldmodel == NULL)
6362 Con_Print("No map loaded.\n");
6365 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6366 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6376 for (;COM_Parse(t, true) && strcmp(
6377 if (COM_Parse(t, true))
6379 if (com_token[0] == '!')
6382 origin[0] = atof(com_token+1);
6385 origin[0] = atof(com_token);
6390 while (*s && *s != '\n' && *s != '\r')
6396 // check for modifier flags
6403 #if _MSC_VER >= 1400
6404 #define sscanf sscanf_s
6406 cubemapname[sizeof(cubemapname)-1] = 0;
6407 #if MAX_QPATH != 128
6408 #error update this code if MAX_QPATH changes
6410 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
6411 #if _MSC_VER >= 1400
6412 , sizeof(cubemapname)
6414 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
6417 flags = LIGHTFLAG_REALTIMEMODE;
6425 coronasizescale = 0.25f;
6427 VectorClear(angles);
6430 if (a < 9 || !strcmp(cubemapname, "\"\""))
6432 // remove quotes on cubemapname
6433 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
6436 namelen = strlen(cubemapname) - 2;
6437 memmove(cubemapname, cubemapname + 1, namelen);
6438 cubemapname[namelen] = '\0';
6442 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);
6445 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6453 Con_Printf("invalid rtlights file \"%s\"\n", name);
6454 Mem_Free(lightsstring);
6458 void R_Shadow_SaveWorldLights(void)
6462 size_t bufchars, bufmaxchars;
6464 char name[MAX_QPATH];
6465 char line[MAX_INPUTLINE];
6466 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
6467 // I hate lines which are 3 times my screen size :( --blub
6470 if (cl.worldmodel == NULL)
6472 Con_Print("No map loaded.\n");
6475 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6476 bufchars = bufmaxchars = 0;
6478 for (lightindex = 0;lightindex < range;lightindex++)
6480 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6483 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
6484 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);
6485 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
6486 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]);
6488 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);
6489 if (bufchars + strlen(line) > bufmaxchars)
6491 bufmaxchars = bufchars + strlen(line) + 2048;
6493 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
6497 memcpy(buf, oldbuf, bufchars);
6503 memcpy(buf + bufchars, line, strlen(line));
6504 bufchars += strlen(line);
6508 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
6513 void R_Shadow_LoadLightsFile(void)
6516 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
6517 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
6518 if (cl.worldmodel == NULL)
6520 Con_Print("No map loaded.\n");
6523 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
6524 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6532 while (*s && *s != '\n' && *s != '\r')
6538 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);
6542 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);
6545 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
6546 radius = bound(15, radius, 4096);
6547 VectorScale(color, (2.0f / (8388608.0f)), color);
6548 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6556 Con_Printf("invalid lights file \"%s\"\n", name);
6557 Mem_Free(lightsstring);
6561 // tyrlite/hmap2 light types in the delay field
6562 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
6564 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
6576 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
6577 char key[256], value[MAX_INPUTLINE];
6580 if (cl.worldmodel == NULL)
6582 Con_Print("No map loaded.\n");
6585 // try to load a .ent file first
6586 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
6587 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
6588 // and if that is not found, fall back to the bsp file entity string
6590 data = cl.worldmodel->brush.entities;
6593 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
6595 type = LIGHTTYPE_MINUSX;
6596 origin[0] = origin[1] = origin[2] = 0;
6597 originhack[0] = originhack[1] = originhack[2] = 0;
6598 angles[0] = angles[1] = angles[2] = 0;
6599 color[0] = color[1] = color[2] = 1;
6600 light[0] = light[1] = light[2] = 1;light[3] = 300;
6601 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
6611 if (!COM_ParseToken_Simple(&data, false, false, true))
6613 if (com_token[0] == '}')
6614 break; // end of entity
6615 if (com_token[0] == '_')
6616 strlcpy(key, com_token + 1, sizeof(key));
6618 strlcpy(key, com_token, sizeof(key));
6619 while (key[strlen(key)-1] == ' ') // remove trailing spaces
6620 key[strlen(key)-1] = 0;
6621 if (!COM_ParseToken_Simple(&data, false, false, true))
6623 strlcpy(value, com_token, sizeof(value));
6625 // now that we have the key pair worked out...
6626 if (!strcmp("light", key))
6628 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
6632 light[0] = vec[0] * (1.0f / 256.0f);
6633 light[1] = vec[0] * (1.0f / 256.0f);
6634 light[2] = vec[0] * (1.0f / 256.0f);
6640 light[0] = vec[0] * (1.0f / 255.0f);
6641 light[1] = vec[1] * (1.0f / 255.0f);
6642 light[2] = vec[2] * (1.0f / 255.0f);
6646 else if (!strcmp("delay", key))
6648 else if (!strcmp("origin", key))
6649 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
6650 else if (!strcmp("angle", key))
6651 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
6652 else if (!strcmp("angles", key))
6653 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
6654 else if (!strcmp("color", key))
6655 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
6656 else if (!strcmp("wait", key))
6657 fadescale = atof(value);
6658 else if (!strcmp("classname", key))
6660 if (!strncmp(value, "light", 5))
6663 if (!strcmp(value, "light_fluoro"))
6668 overridecolor[0] = 1;
6669 overridecolor[1] = 1;
6670 overridecolor[2] = 1;
6672 if (!strcmp(value, "light_fluorospark"))
6677 overridecolor[0] = 1;
6678 overridecolor[1] = 1;
6679 overridecolor[2] = 1;
6681 if (!strcmp(value, "light_globe"))
6686 overridecolor[0] = 1;
6687 overridecolor[1] = 0.8;
6688 overridecolor[2] = 0.4;
6690 if (!strcmp(value, "light_flame_large_yellow"))
6695 overridecolor[0] = 1;
6696 overridecolor[1] = 0.5;
6697 overridecolor[2] = 0.1;
6699 if (!strcmp(value, "light_flame_small_yellow"))
6704 overridecolor[0] = 1;
6705 overridecolor[1] = 0.5;
6706 overridecolor[2] = 0.1;
6708 if (!strcmp(value, "light_torch_small_white"))
6713 overridecolor[0] = 1;
6714 overridecolor[1] = 0.5;
6715 overridecolor[2] = 0.1;
6717 if (!strcmp(value, "light_torch_small_walltorch"))
6722 overridecolor[0] = 1;
6723 overridecolor[1] = 0.5;
6724 overridecolor[2] = 0.1;
6728 else if (!strcmp("style", key))
6729 style = atoi(value);
6730 else if (!strcmp("skin", key))
6731 skin = (int)atof(value);
6732 else if (!strcmp("pflags", key))
6733 pflags = (int)atof(value);
6734 //else if (!strcmp("effects", key))
6735 // effects = (int)atof(value);
6736 else if (cl.worldmodel->type == mod_brushq3)
6738 if (!strcmp("scale", key))
6739 lightscale = atof(value);
6740 if (!strcmp("fade", key))
6741 fadescale = atof(value);
6746 if (lightscale <= 0)
6750 if (color[0] == color[1] && color[0] == color[2])
6752 color[0] *= overridecolor[0];
6753 color[1] *= overridecolor[1];
6754 color[2] *= overridecolor[2];
6756 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
6757 color[0] = color[0] * light[0];
6758 color[1] = color[1] * light[1];
6759 color[2] = color[2] * light[2];
6762 case LIGHTTYPE_MINUSX:
6764 case LIGHTTYPE_RECIPX:
6766 VectorScale(color, (1.0f / 16.0f), color);
6768 case LIGHTTYPE_RECIPXX:
6770 VectorScale(color, (1.0f / 16.0f), color);
6773 case LIGHTTYPE_NONE:
6777 case LIGHTTYPE_MINUSXX:
6780 VectorAdd(origin, originhack, origin);
6782 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);
6785 Mem_Free(entfiledata);
6789 static void R_Shadow_SetCursorLocationForView(void)
6792 vec3_t dest, endpos;
6794 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
6795 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
6796 if (trace.fraction < 1)
6798 dist = trace.fraction * r_editlights_cursordistance.value;
6799 push = r_editlights_cursorpushback.value;
6803 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
6804 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
6808 VectorClear( endpos );
6810 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6811 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6812 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6815 void R_Shadow_UpdateWorldLightSelection(void)
6817 if (r_editlights.integer)
6819 R_Shadow_SetCursorLocationForView();
6820 R_Shadow_SelectLightInView();
6823 R_Shadow_SelectLight(NULL);
6826 static void R_Shadow_EditLights_Clear_f(void)
6828 R_Shadow_ClearWorldLights();
6831 void R_Shadow_EditLights_Reload_f(void)
6835 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
6836 R_Shadow_ClearWorldLights();
6837 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
6839 R_Shadow_LoadWorldLights();
6840 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6841 R_Shadow_LoadLightsFile();
6843 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
6845 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6846 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6850 static void R_Shadow_EditLights_Save_f(void)
6854 R_Shadow_SaveWorldLights();
6857 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6859 R_Shadow_ClearWorldLights();
6860 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6863 static void R_Shadow_EditLights_ImportLightsFile_f(void)
6865 R_Shadow_ClearWorldLights();
6866 R_Shadow_LoadLightsFile();
6869 static void R_Shadow_EditLights_Spawn_f(void)
6872 if (!r_editlights.integer)
6874 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6877 if (Cmd_Argc() != 1)
6879 Con_Print("r_editlights_spawn does not take parameters\n");
6882 color[0] = color[1] = color[2] = 1;
6883 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6886 static void R_Shadow_EditLights_Edit_f(void)
6888 vec3_t origin, angles, color;
6889 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6890 int style, shadows, flags, normalmode, realtimemode;
6891 char cubemapname[MAX_INPUTLINE];
6892 if (!r_editlights.integer)
6894 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6897 if (!r_shadow_selectedlight)
6899 Con_Print("No selected light.\n");
6902 VectorCopy(r_shadow_selectedlight->origin, origin);
6903 VectorCopy(r_shadow_selectedlight->angles, angles);
6904 VectorCopy(r_shadow_selectedlight->color, color);
6905 radius = r_shadow_selectedlight->radius;
6906 style = r_shadow_selectedlight->style;
6907 if (r_shadow_selectedlight->cubemapname)
6908 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6911 shadows = r_shadow_selectedlight->shadow;
6912 corona = r_shadow_selectedlight->corona;
6913 coronasizescale = r_shadow_selectedlight->coronasizescale;
6914 ambientscale = r_shadow_selectedlight->ambientscale;
6915 diffusescale = r_shadow_selectedlight->diffusescale;
6916 specularscale = r_shadow_selectedlight->specularscale;
6917 flags = r_shadow_selectedlight->flags;
6918 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6919 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6920 if (!strcmp(Cmd_Argv(1), "origin"))
6922 if (Cmd_Argc() != 5)
6924 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6927 origin[0] = atof(Cmd_Argv(2));
6928 origin[1] = atof(Cmd_Argv(3));
6929 origin[2] = atof(Cmd_Argv(4));
6931 else if (!strcmp(Cmd_Argv(1), "originscale"))
6933 if (Cmd_Argc() != 5)
6935 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6938 origin[0] *= atof(Cmd_Argv(2));
6939 origin[1] *= atof(Cmd_Argv(3));
6940 origin[2] *= atof(Cmd_Argv(4));
6942 else if (!strcmp(Cmd_Argv(1), "originx"))
6944 if (Cmd_Argc() != 3)
6946 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6949 origin[0] = atof(Cmd_Argv(2));
6951 else if (!strcmp(Cmd_Argv(1), "originy"))
6953 if (Cmd_Argc() != 3)
6955 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6958 origin[1] = atof(Cmd_Argv(2));
6960 else if (!strcmp(Cmd_Argv(1), "originz"))
6962 if (Cmd_Argc() != 3)
6964 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6967 origin[2] = atof(Cmd_Argv(2));
6969 else if (!strcmp(Cmd_Argv(1), "move"))
6971 if (Cmd_Argc() != 5)
6973 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6976 origin[0] += atof(Cmd_Argv(2));
6977 origin[1] += atof(Cmd_Argv(3));
6978 origin[2] += atof(Cmd_Argv(4));
6980 else if (!strcmp(Cmd_Argv(1), "movex"))
6982 if (Cmd_Argc() != 3)
6984 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6987 origin[0] += atof(Cmd_Argv(2));
6989 else if (!strcmp(Cmd_Argv(1), "movey"))
6991 if (Cmd_Argc() != 3)
6993 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6996 origin[1] += atof(Cmd_Argv(2));
6998 else if (!strcmp(Cmd_Argv(1), "movez"))
7000 if (Cmd_Argc() != 3)
7002 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7005 origin[2] += atof(Cmd_Argv(2));
7007 else if (!strcmp(Cmd_Argv(1), "angles"))
7009 if (Cmd_Argc() != 5)
7011 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
7014 angles[0] = atof(Cmd_Argv(2));
7015 angles[1] = atof(Cmd_Argv(3));
7016 angles[2] = atof(Cmd_Argv(4));
7018 else if (!strcmp(Cmd_Argv(1), "anglesx"))
7020 if (Cmd_Argc() != 3)
7022 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7025 angles[0] = atof(Cmd_Argv(2));
7027 else if (!strcmp(Cmd_Argv(1), "anglesy"))
7029 if (Cmd_Argc() != 3)
7031 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7034 angles[1] = atof(Cmd_Argv(2));
7036 else if (!strcmp(Cmd_Argv(1), "anglesz"))
7038 if (Cmd_Argc() != 3)
7040 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7043 angles[2] = atof(Cmd_Argv(2));
7045 else if (!strcmp(Cmd_Argv(1), "color"))
7047 if (Cmd_Argc() != 5)
7049 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
7052 color[0] = atof(Cmd_Argv(2));
7053 color[1] = atof(Cmd_Argv(3));
7054 color[2] = atof(Cmd_Argv(4));
7056 else if (!strcmp(Cmd_Argv(1), "radius"))
7058 if (Cmd_Argc() != 3)
7060 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7063 radius = atof(Cmd_Argv(2));
7065 else if (!strcmp(Cmd_Argv(1), "colorscale"))
7067 if (Cmd_Argc() == 3)
7069 double scale = atof(Cmd_Argv(2));
7076 if (Cmd_Argc() != 5)
7078 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
7081 color[0] *= atof(Cmd_Argv(2));
7082 color[1] *= atof(Cmd_Argv(3));
7083 color[2] *= atof(Cmd_Argv(4));
7086 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
7088 if (Cmd_Argc() != 3)
7090 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7093 radius *= atof(Cmd_Argv(2));
7095 else if (!strcmp(Cmd_Argv(1), "style"))
7097 if (Cmd_Argc() != 3)
7099 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7102 style = atoi(Cmd_Argv(2));
7104 else if (!strcmp(Cmd_Argv(1), "cubemap"))
7108 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7111 if (Cmd_Argc() == 3)
7112 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
7116 else if (!strcmp(Cmd_Argv(1), "shadows"))
7118 if (Cmd_Argc() != 3)
7120 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7123 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7125 else if (!strcmp(Cmd_Argv(1), "corona"))
7127 if (Cmd_Argc() != 3)
7129 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7132 corona = atof(Cmd_Argv(2));
7134 else if (!strcmp(Cmd_Argv(1), "coronasize"))
7136 if (Cmd_Argc() != 3)
7138 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7141 coronasizescale = atof(Cmd_Argv(2));
7143 else if (!strcmp(Cmd_Argv(1), "ambient"))
7145 if (Cmd_Argc() != 3)
7147 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7150 ambientscale = atof(Cmd_Argv(2));
7152 else if (!strcmp(Cmd_Argv(1), "diffuse"))
7154 if (Cmd_Argc() != 3)
7156 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7159 diffusescale = atof(Cmd_Argv(2));
7161 else if (!strcmp(Cmd_Argv(1), "specular"))
7163 if (Cmd_Argc() != 3)
7165 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7168 specularscale = atof(Cmd_Argv(2));
7170 else if (!strcmp(Cmd_Argv(1), "normalmode"))
7172 if (Cmd_Argc() != 3)
7174 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7177 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7179 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
7181 if (Cmd_Argc() != 3)
7183 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7186 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7190 Con_Print("usage: r_editlights_edit [property] [value]\n");
7191 Con_Print("Selected light's properties:\n");
7192 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7193 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7194 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7195 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
7196 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
7197 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
7198 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
7199 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
7200 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
7201 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
7202 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
7203 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
7204 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
7205 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
7208 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
7209 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
7212 static void R_Shadow_EditLights_EditAll_f(void)
7215 dlight_t *light, *oldselected;
7218 if (!r_editlights.integer)
7220 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
7224 oldselected = r_shadow_selectedlight;
7225 // EditLights doesn't seem to have a "remove" command or something so:
7226 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7227 for (lightindex = 0;lightindex < range;lightindex++)
7229 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7232 R_Shadow_SelectLight(light);
7233 R_Shadow_EditLights_Edit_f();
7235 // return to old selected (to not mess editing once selection is locked)
7236 R_Shadow_SelectLight(oldselected);
7239 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
7241 int lightnumber, lightcount;
7242 size_t lightindex, range;
7247 if (!r_editlights.integer)
7250 // update cvars so QC can query them
7251 if (r_shadow_selectedlight)
7253 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7254 Cvar_SetQuick(&r_editlights_current_origin, temp);
7255 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7256 Cvar_SetQuick(&r_editlights_current_angles, temp);
7257 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7258 Cvar_SetQuick(&r_editlights_current_color, temp);
7259 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
7260 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
7261 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
7262 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
7263 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
7264 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
7265 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
7266 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
7267 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
7268 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
7269 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
7272 // draw properties on screen
7273 if (!r_editlights_drawproperties.integer)
7275 x = vid_conwidth.value - 320;
7277 DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
7280 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7281 for (lightindex = 0;lightindex < range;lightindex++)
7283 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7286 if (light == r_shadow_selectedlight)
7287 lightnumber = (int)lightindex;
7290 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;
7291 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;
7293 if (r_shadow_selectedlight == NULL)
7295 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;
7296 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;
7297 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;
7298 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;
7299 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;
7300 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;
7301 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;
7302 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;
7303 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;
7304 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;
7305 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;
7306 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;
7307 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;
7308 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;
7309 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;
7311 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;
7312 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;
7313 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;
7314 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;
7315 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;
7316 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;
7317 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;
7318 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;
7319 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;
7320 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;
7323 static void R_Shadow_EditLights_ToggleShadow_f(void)
7325 if (!r_editlights.integer)
7327 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7330 if (!r_shadow_selectedlight)
7332 Con_Print("No selected light.\n");
7335 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);
7338 static void R_Shadow_EditLights_ToggleCorona_f(void)
7340 if (!r_editlights.integer)
7342 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7345 if (!r_shadow_selectedlight)
7347 Con_Print("No selected light.\n");
7350 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);
7353 static void R_Shadow_EditLights_Remove_f(void)
7355 if (!r_editlights.integer)
7357 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
7360 if (!r_shadow_selectedlight)
7362 Con_Print("No selected light.\n");
7365 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
7366 r_shadow_selectedlight = NULL;
7369 static void R_Shadow_EditLights_Help_f(void)
7372 "Documentation on r_editlights system:\n"
7374 "r_editlights : enable/disable editing mode\n"
7375 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
7376 "r_editlights_cursorpushback : push back cursor this far from surface\n"
7377 "r_editlights_cursorpushoff : push cursor off surface this far\n"
7378 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
7379 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
7381 "r_editlights_help : this help\n"
7382 "r_editlights_clear : remove all lights\n"
7383 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
7384 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
7385 "r_editlights_save : save to .rtlights file\n"
7386 "r_editlights_spawn : create a light with default settings\n"
7387 "r_editlights_edit command : edit selected light - more documentation below\n"
7388 "r_editlights_remove : remove selected light\n"
7389 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
7390 "r_editlights_importlightentitiesfrommap : reload light entities\n"
7391 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
7393 "origin x y z : set light location\n"
7394 "originx x: set x component of light location\n"
7395 "originy y: set y component of light location\n"
7396 "originz z: set z component of light location\n"
7397 "move x y z : adjust light location\n"
7398 "movex x: adjust x component of light location\n"
7399 "movey y: adjust y component of light location\n"
7400 "movez z: adjust z component of light location\n"
7401 "angles x y z : set light angles\n"
7402 "anglesx x: set x component of light angles\n"
7403 "anglesy y: set y component of light angles\n"
7404 "anglesz z: set z component of light angles\n"
7405 "color r g b : set color of light (can be brighter than 1 1 1)\n"
7406 "radius radius : set radius (size) of light\n"
7407 "colorscale grey : multiply color of light (1 does nothing)\n"
7408 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
7409 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
7410 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
7411 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
7412 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
7413 "cubemap basename : set filter cubemap of light\n"
7414 "shadows 1/0 : turn on/off shadows\n"
7415 "corona n : set corona intensity\n"
7416 "coronasize n : set corona size (0-1)\n"
7417 "ambient n : set ambient intensity (0-1)\n"
7418 "diffuse n : set diffuse intensity (0-1)\n"
7419 "specular n : set specular intensity (0-1)\n"
7420 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
7421 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
7422 "<nothing> : print light properties to console\n"
7426 static void R_Shadow_EditLights_CopyInfo_f(void)
7428 if (!r_editlights.integer)
7430 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
7433 if (!r_shadow_selectedlight)
7435 Con_Print("No selected light.\n");
7438 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
7439 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
7440 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
7441 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
7442 if (r_shadow_selectedlight->cubemapname)
7443 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
7445 r_shadow_bufferlight.cubemapname[0] = 0;
7446 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
7447 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
7448 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
7449 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
7450 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
7451 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
7452 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
7455 static void R_Shadow_EditLights_PasteInfo_f(void)
7457 if (!r_editlights.integer)
7459 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
7462 if (!r_shadow_selectedlight)
7464 Con_Print("No selected light.\n");
7467 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);
7470 static void R_Shadow_EditLights_Lock_f(void)
7472 if (!r_editlights.integer)
7474 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
7477 if (r_editlights_lockcursor)
7479 r_editlights_lockcursor = false;
7482 if (!r_shadow_selectedlight)
7484 Con_Print("No selected light to lock on.\n");
7487 r_editlights_lockcursor = true;
7490 static void R_Shadow_EditLights_Init(void)
7492 Cvar_RegisterVariable(&r_editlights);
7493 Cvar_RegisterVariable(&r_editlights_cursordistance);
7494 Cvar_RegisterVariable(&r_editlights_cursorpushback);
7495 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
7496 Cvar_RegisterVariable(&r_editlights_cursorgrid);
7497 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
7498 Cvar_RegisterVariable(&r_editlights_drawproperties);
7499 Cvar_RegisterVariable(&r_editlights_current_origin);
7500 Cvar_RegisterVariable(&r_editlights_current_angles);
7501 Cvar_RegisterVariable(&r_editlights_current_color);
7502 Cvar_RegisterVariable(&r_editlights_current_radius);
7503 Cvar_RegisterVariable(&r_editlights_current_corona);
7504 Cvar_RegisterVariable(&r_editlights_current_coronasize);
7505 Cvar_RegisterVariable(&r_editlights_current_style);
7506 Cvar_RegisterVariable(&r_editlights_current_shadows);
7507 Cvar_RegisterVariable(&r_editlights_current_cubemap);
7508 Cvar_RegisterVariable(&r_editlights_current_ambient);
7509 Cvar_RegisterVariable(&r_editlights_current_diffuse);
7510 Cvar_RegisterVariable(&r_editlights_current_specular);
7511 Cvar_RegisterVariable(&r_editlights_current_normalmode);
7512 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
7513 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
7514 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
7515 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)");
7516 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
7517 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
7518 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
7519 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)");
7520 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
7521 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
7522 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
7523 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
7524 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
7525 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
7526 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)");
7527 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
7533 =============================================================================
7537 =============================================================================
7540 void R_CompleteLightPoint(float *ambient, float *diffuse, float *lightdir, const vec3_t p, const int flags, float lightmapintensity, float ambientintensity)
7542 int i, numlights, flag, q;
7545 float relativepoint[3];
7550 float sa[3], sx[3], sy[3], sz[3], sd[3];
7553 // use first order spherical harmonics to combine directional lights
7554 for (q = 0; q < 3; q++)
7555 sa[q] = sx[q] = sy[q] = sz[q] = sd[q] = 0;
7557 if (flags & LP_LIGHTMAP)
7559 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7561 float tempambient[3];
7562 for (q = 0; q < 3; q++)
7563 tempambient[q] = color[q] = relativepoint[q] = 0;
7564 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
7565 // calculate a weighted average light direction as well
7566 intensity = VectorLength(color);
7567 for (q = 0; q < 3; q++)
7569 sa[q] += (0.5f * color[q] + tempambient[q]) * lightmapintensity;
7570 sx[q] += (relativepoint[0] * color[q]) * lightmapintensity;
7571 sy[q] += (relativepoint[1] * color[q]) * lightmapintensity;
7572 sz[q] += (relativepoint[2] * color[q]) * lightmapintensity;
7573 sd[q] += (intensity * relativepoint[q]) * lightmapintensity;
7578 // unlit map - fullbright but scaled by lightmapintensity
7579 for (q = 0; q < 3; q++)
7580 sa[q] += lightmapintensity;
7584 if (flags & LP_RTWORLD)
7586 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7587 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7588 for (i = 0; i < numlights; i++)
7590 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7593 light = &dlight->rtlight;
7594 if (!(light->flags & flag))
7597 lightradius2 = light->radius * light->radius;
7598 VectorSubtract(light->shadoworigin, p, relativepoint);
7599 dist2 = VectorLength2(relativepoint);
7600 if (dist2 >= lightradius2)
7602 dist = sqrt(dist2) / light->radius;
7603 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
7604 if (intensity <= 0.0f)
7606 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
7608 for (q = 0; q < 3; q++)
7609 color[q] = light->currentcolor[q] * intensity;
7610 intensity = VectorLength(color);
7611 VectorNormalize(relativepoint);
7612 for (q = 0; q < 3; q++)
7614 sa[q] += 0.5f * color[q];
7615 sx[q] += relativepoint[0] * color[q];
7616 sy[q] += relativepoint[1] * color[q];
7617 sz[q] += relativepoint[2] * color[q];
7618 sd[q] += intensity * relativepoint[q];
7621 // FIXME: sample bouncegrid too!
7624 if (flags & LP_DYNLIGHT)
7627 for (i = 0;i < r_refdef.scene.numlights;i++)
7629 light = r_refdef.scene.lights[i];
7631 lightradius2 = light->radius * light->radius;
7632 VectorSubtract(light->shadoworigin, p, relativepoint);
7633 dist2 = VectorLength2(relativepoint);
7634 if (dist2 >= lightradius2)
7636 dist = sqrt(dist2) / light->radius;
7637 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
7638 if (intensity <= 0.0f)
7640 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
7642 for (q = 0; q < 3; q++)
7643 color[q] = light->currentcolor[q] * intensity;
7644 intensity = VectorLength(color);
7645 VectorNormalize(relativepoint);
7646 for (q = 0; q < 3; q++)
7648 sa[q] += 0.5f * color[q];
7649 sx[q] += relativepoint[0] * color[q];
7650 sy[q] += relativepoint[1] * color[q];
7651 sz[q] += relativepoint[2] * color[q];
7652 sd[q] += intensity * relativepoint[q];
7657 // calculate the weighted-average light direction (bentnormal)
7658 for (q = 0; q < 3; q++)
7659 lightdir[q] = sd[q];
7660 VectorNormalize(lightdir);
7661 for (q = 0; q < 3; q++)
7663 // extract the diffuse color along the chosen direction and scale it
7664 diffuse[q] = (lightdir[0] * sx[q] + lightdir[1] * sy[q] + lightdir[2] * sz[q]);
7665 // subtract some of diffuse from ambient
7666 ambient[q] = sa[q] + -0.333f * diffuse[q] + ambientintensity;