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"
143 static void R_Shadow_EditLights_Init(void);
145 typedef enum r_shadow_rendermode_e
147 R_SHADOW_RENDERMODE_NONE,
148 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
149 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
150 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
151 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
152 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
153 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
154 R_SHADOW_RENDERMODE_LIGHT_GLSL,
155 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
156 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
157 R_SHADOW_RENDERMODE_SHADOWMAP2D
159 r_shadow_rendermode_t;
161 typedef enum r_shadow_shadowmode_e
163 R_SHADOW_SHADOWMODE_STENCIL,
164 R_SHADOW_SHADOWMODE_SHADOWMAP2D
166 r_shadow_shadowmode_t;
168 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
169 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
170 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
171 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
172 int r_shadow_scenemaxlights;
173 int r_shadow_scenenumlights;
174 rtlight_t **r_shadow_scenelightlist; // includes both static lights and dlights, as filtered by appropriate flags
175 qboolean r_shadow_usingshadowmap2d;
176 qboolean r_shadow_usingshadowmaportho;
177 int r_shadow_shadowmapside;
178 float r_shadow_lightshadowmap_texturescale[4]; // xy = scale, zw = offset
179 float r_shadow_lightshadowmap_parameters[4]; // x = frustum width in pixels (excludes border), y = z scale, z = size of viewport, w = z center
180 float r_shadow_modelshadowmap_texturescale[4]; // xy = scale, zw = offset
181 float r_shadow_modelshadowmap_parameters[4]; // xyz = scale, w = shadow brightness
183 int r_shadow_drawbuffer;
184 int r_shadow_readbuffer;
186 int r_shadow_cullface_front, r_shadow_cullface_back;
187 GLuint r_shadow_fbo2d;
188 r_shadow_shadowmode_t r_shadow_shadowmode;
189 int r_shadow_shadowmapfilterquality;
190 int r_shadow_shadowmapdepthbits;
191 int r_shadow_shadowmapmaxsize;
192 int r_shadow_shadowmaptexturesize;
193 qboolean r_shadow_shadowmapvsdct;
194 qboolean r_shadow_shadowmapsampler;
195 qboolean r_shadow_shadowmapshadowsampler;
196 int r_shadow_shadowmappcf;
197 int r_shadow_shadowmapborder;
198 matrix4x4_t r_shadow_shadowmapmatrix;
199 int r_shadow_lightscissor[4];
200 qboolean r_shadow_usingdeferredprepass;
201 qboolean r_shadow_shadowmapdepthtexture;
202 mod_alloclightmap_state_t r_shadow_shadowmapatlas_state;
203 int r_shadow_shadowmapatlas_modelshadows_x;
204 int r_shadow_shadowmapatlas_modelshadows_y;
205 int r_shadow_shadowmapatlas_modelshadows_size;
206 int maxshadowtriangles;
209 int maxshadowvertices;
210 float *shadowvertex3f;
220 unsigned char *shadowsides;
221 int *shadowsideslist;
228 int r_shadow_buffer_numleafpvsbytes;
229 unsigned char *r_shadow_buffer_visitingleafpvs;
230 unsigned char *r_shadow_buffer_leafpvs;
231 int *r_shadow_buffer_leaflist;
233 int r_shadow_buffer_numsurfacepvsbytes;
234 unsigned char *r_shadow_buffer_surfacepvs;
235 int *r_shadow_buffer_surfacelist;
236 unsigned char *r_shadow_buffer_surfacesides;
238 int r_shadow_buffer_numshadowtrispvsbytes;
239 unsigned char *r_shadow_buffer_shadowtrispvs;
240 int r_shadow_buffer_numlighttrispvsbytes;
241 unsigned char *r_shadow_buffer_lighttrispvs;
243 rtexturepool_t *r_shadow_texturepool;
244 rtexture_t *r_shadow_attenuationgradienttexture;
245 rtexture_t *r_shadow_attenuation2dtexture;
246 rtexture_t *r_shadow_attenuation3dtexture;
247 skinframe_t *r_shadow_lightcorona;
248 rtexture_t *r_shadow_shadowmap2ddepthbuffer;
249 rtexture_t *r_shadow_shadowmap2ddepthtexture;
250 rtexture_t *r_shadow_shadowmapvsdcttexture;
252 GLuint r_shadow_prepassgeometryfbo;
253 GLuint r_shadow_prepasslightingdiffusespecularfbo;
254 GLuint r_shadow_prepasslightingdiffusefbo;
255 int r_shadow_prepass_width;
256 int r_shadow_prepass_height;
257 rtexture_t *r_shadow_prepassgeometrydepthbuffer;
258 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
259 rtexture_t *r_shadow_prepasslightingdiffusetexture;
260 rtexture_t *r_shadow_prepasslightingspeculartexture;
262 int r_shadow_viewfbo;
263 rtexture_t *r_shadow_viewdepthtexture;
264 rtexture_t *r_shadow_viewcolortexture;
267 int r_shadow_viewwidth;
268 int r_shadow_viewheight;
270 // lights are reloaded when this changes
271 char r_shadow_mapname[MAX_QPATH];
273 // buffer for doing corona fading
274 unsigned int r_shadow_occlusion_buf = 0;
276 // used only for light filters (cubemaps)
277 rtexturepool_t *r_shadow_filters_texturepool;
279 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"};
280 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"};
281 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
282 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"};
283 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)"};
284 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
285 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)"};
286 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"};
287 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
288 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
289 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
290 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
291 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
292 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
293 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
294 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
295 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
296 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)"};
297 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
298 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
299 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
300 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
301 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)"};
302 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)"};
303 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"};
304 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
305 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
306 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"};
307 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)"};
308 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
309 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)"};
310 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "1", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes"};
311 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)"};
312 cvar_t r_shadow_shadowmapping_useshadowsampler = {CVAR_SAVE, "r_shadow_shadowmapping_useshadowsampler", "1", "whether to use sampler2DShadow if available"};
313 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
314 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
315 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"};
316 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..."};
317 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"};
318 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"};
319 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
320 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
321 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "5", "shadowmap size bias for filtering"};
322 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
323 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
324 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
325 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
326 cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
327 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
328 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)"};
329 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)"};
330 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"};
331 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"};
332 cvar_t r_shadow_culllights_trace_eyejitter = {CVAR_SAVE, "r_shadow_culllights_trace_eyejitter", "16", "offset eye location randomly by this much"};
333 cvar_t r_shadow_culllights_trace_enlarge = {CVAR_SAVE, "r_shadow_culllights_trace_enlarge", "0", "make light bounds bigger by *(1.0+enlarge)"};
334 cvar_t r_shadow_culllights_trace_expand = {CVAR_SAVE, "r_shadow_culllights_trace_expand", "8", "make light bounds bigger by this many units"};
335 cvar_t r_shadow_culllights_trace_pad = {CVAR_SAVE, "r_shadow_culllights_trace_expand", "8", "accept traces that hit within this many units of the light bounds"};
336 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)"};
337 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)"};
338 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"};
339 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)"};
340 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"};
341 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"};
342 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" };
343 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)"};
344 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"};
345 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"};
346 cvar_t r_shadow_bouncegrid_dynamic_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
347 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)"};
348 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)"};
349 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"};
350 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)"};
351 cvar_t r_shadow_bouncegrid_dynamic_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_spacing", "64", "unit size of bouncegrid pixel"};
352 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"};
353 cvar_t r_shadow_bouncegrid_dynamic_x = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_x", "64", "maximum texture size of bouncegrid on X axis"};
354 cvar_t r_shadow_bouncegrid_dynamic_y = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_y", "64", "maximum texture size of bouncegrid on Y axis"};
355 cvar_t r_shadow_bouncegrid_dynamic_z = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_z", "32", "maximum texture size of bouncegrid on Z axis"};
356 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"};
357 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)"};
358 cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
359 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"};
360 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"};
361 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)" };
362 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"};
363 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "0.25", "brightness of particles contributing to bouncegrid texture"};
364 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" };
365 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)" };
366 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"};
367 cvar_t r_shadow_bouncegrid_static = {CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
368 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" };
369 cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
370 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"};
371 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"};
372 cvar_t r_shadow_bouncegrid_static_maxphotons = {CVAR_SAVE, "r_shadow_bouncegrid_static_maxphotons", "250000", "upper bound on photons in static mode"};
373 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)" };
374 cvar_t r_shadow_bouncegrid_static_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_static_spacing", "64", "unit size of bouncegrid pixel when in static mode"};
375 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
376 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"};
377 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!"};
378 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
379 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
380 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
381 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
382 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
383 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
384 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
385 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
386 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
387 cvar_t r_editlights_drawproperties = {0, "r_editlights_drawproperties", "1", "draw properties of currently selected light"};
388 cvar_t r_editlights_current_origin = {0, "r_editlights_current_origin", "0 0 0", "origin of selected light"};
389 cvar_t r_editlights_current_angles = {0, "r_editlights_current_angles", "0 0 0", "angles of selected light"};
390 cvar_t r_editlights_current_color = {0, "r_editlights_current_color", "1 1 1", "color of selected light"};
391 cvar_t r_editlights_current_radius = {0, "r_editlights_current_radius", "0", "radius of selected light"};
392 cvar_t r_editlights_current_corona = {0, "r_editlights_current_corona", "0", "corona intensity of selected light"};
393 cvar_t r_editlights_current_coronasize = {0, "r_editlights_current_coronasize", "0", "corona size of selected light"};
394 cvar_t r_editlights_current_style = {0, "r_editlights_current_style", "0", "style of selected light"};
395 cvar_t r_editlights_current_shadows = {0, "r_editlights_current_shadows", "0", "shadows flag of selected light"};
396 cvar_t r_editlights_current_cubemap = {0, "r_editlights_current_cubemap", "0", "cubemap of selected light"};
397 cvar_t r_editlights_current_ambient = {0, "r_editlights_current_ambient", "0", "ambient intensity of selected light"};
398 cvar_t r_editlights_current_diffuse = {0, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"};
399 cvar_t r_editlights_current_specular = {0, "r_editlights_current_specular", "1", "specular intensity of selected light"};
400 cvar_t r_editlights_current_normalmode = {0, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"};
401 cvar_t r_editlights_current_realtimemode = {0, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"};
403 r_shadow_bouncegrid_state_t r_shadow_bouncegrid_state;
405 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
406 #define ATTENTABLESIZE 256
407 // 1D gradient, 2D circle and 3D sphere attenuation textures
408 #define ATTEN1DSIZE 32
409 #define ATTEN2DSIZE 64
410 #define ATTEN3DSIZE 32
412 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
413 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
414 static float r_shadow_attentable[ATTENTABLESIZE+1];
416 rtlight_t *r_shadow_compilingrtlight;
417 static memexpandablearray_t r_shadow_worldlightsarray;
418 dlight_t *r_shadow_selectedlight;
419 dlight_t r_shadow_bufferlight;
420 vec3_t r_editlights_cursorlocation;
421 qboolean r_editlights_lockcursor;
423 extern int con_vislines;
425 void R_Shadow_UncompileWorldLights(void);
426 void R_Shadow_ClearWorldLights(void);
427 void R_Shadow_SaveWorldLights(void);
428 void R_Shadow_LoadWorldLights(void);
429 void R_Shadow_LoadLightsFile(void);
430 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
431 void R_Shadow_EditLights_Reload_f(void);
432 void R_Shadow_ValidateCvars(void);
433 static void R_Shadow_MakeTextures(void);
435 #define EDLIGHTSPRSIZE 8
436 skinframe_t *r_editlights_sprcursor;
437 skinframe_t *r_editlights_sprlight;
438 skinframe_t *r_editlights_sprnoshadowlight;
439 skinframe_t *r_editlights_sprcubemaplight;
440 skinframe_t *r_editlights_sprcubemapnoshadowlight;
441 skinframe_t *r_editlights_sprselection;
443 static void R_Shadow_DrawModelShadowMaps(void);
444 static void R_Shadow_MakeShadowMap(int texturesize);
445 static void R_Shadow_MakeVSDCT(void);
446 static void R_Shadow_SetShadowMode(void)
448 r_shadow_shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
449 r_shadow_shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
450 r_shadow_shadowmapmaxsize = bound(r_shadow_shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, r_shadow_shadowmaptexturesize / 8);
451 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
452 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
453 r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
454 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
455 r_shadow_shadowmapsampler = false;
456 r_shadow_shadowmappcf = 0;
457 r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
458 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
459 Mod_AllocLightmap_Init(&r_shadow_shadowmapatlas_state, r_main_mempool, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize);
460 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
462 switch(vid.renderpath)
464 case RENDERPATH_GL20:
465 if(r_shadow_shadowmapfilterquality < 0)
467 if (!r_fb.usedepthtextures)
468 r_shadow_shadowmappcf = 1;
469 else if((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && vid.support.arb_shadow && r_shadow_shadowmapshadowsampler)
471 r_shadow_shadowmapsampler = true;
472 r_shadow_shadowmappcf = 1;
474 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
475 r_shadow_shadowmappcf = 1;
476 else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa"))
477 r_shadow_shadowmappcf = 1;
479 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
483 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
484 switch (r_shadow_shadowmapfilterquality)
489 r_shadow_shadowmappcf = 1;
492 r_shadow_shadowmappcf = 1;
495 r_shadow_shadowmappcf = 2;
499 if (!r_fb.usedepthtextures)
500 r_shadow_shadowmapsampler = false;
501 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
503 case RENDERPATH_GLES2:
508 if(R_CompileShader_CheckStaticParms())
512 qboolean R_Shadow_ShadowMappingEnabled(void)
514 switch (r_shadow_shadowmode)
516 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
523 static void R_Shadow_FreeShadowMaps(void)
525 Mod_AllocLightmap_Free(&r_shadow_shadowmapatlas_state);
527 R_Shadow_SetShadowMode();
529 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
533 if (r_shadow_shadowmap2ddepthtexture)
534 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
535 r_shadow_shadowmap2ddepthtexture = NULL;
537 if (r_shadow_shadowmap2ddepthbuffer)
538 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
539 r_shadow_shadowmap2ddepthbuffer = NULL;
541 if (r_shadow_shadowmapvsdcttexture)
542 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
543 r_shadow_shadowmapvsdcttexture = NULL;
546 static void r_shadow_start(void)
548 // allocate vertex processing arrays
549 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
550 r_shadow_attenuationgradienttexture = NULL;
551 r_shadow_attenuation2dtexture = NULL;
552 r_shadow_attenuation3dtexture = NULL;
553 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
554 r_shadow_shadowmap2ddepthtexture = NULL;
555 r_shadow_shadowmap2ddepthbuffer = NULL;
556 r_shadow_shadowmapvsdcttexture = NULL;
557 r_shadow_shadowmapmaxsize = 0;
558 r_shadow_shadowmaptexturesize = 0;
559 r_shadow_shadowmapfilterquality = -1;
560 r_shadow_shadowmapdepthbits = 0;
561 r_shadow_shadowmapvsdct = false;
562 r_shadow_shadowmapsampler = false;
563 r_shadow_shadowmappcf = 0;
566 R_Shadow_FreeShadowMaps();
568 r_shadow_texturepool = NULL;
569 r_shadow_filters_texturepool = NULL;
570 R_Shadow_ValidateCvars();
571 R_Shadow_MakeTextures();
572 r_shadow_scenemaxlights = 0;
573 r_shadow_scenenumlights = 0;
574 r_shadow_scenelightlist = NULL;
575 maxshadowtriangles = 0;
576 shadowelements = NULL;
577 maxshadowvertices = 0;
578 shadowvertex3f = NULL;
586 shadowmarklist = NULL;
591 shadowsideslist = NULL;
592 r_shadow_buffer_numleafpvsbytes = 0;
593 r_shadow_buffer_visitingleafpvs = NULL;
594 r_shadow_buffer_leafpvs = NULL;
595 r_shadow_buffer_leaflist = NULL;
596 r_shadow_buffer_numsurfacepvsbytes = 0;
597 r_shadow_buffer_surfacepvs = NULL;
598 r_shadow_buffer_surfacelist = NULL;
599 r_shadow_buffer_surfacesides = NULL;
600 r_shadow_buffer_numshadowtrispvsbytes = 0;
601 r_shadow_buffer_shadowtrispvs = NULL;
602 r_shadow_buffer_numlighttrispvsbytes = 0;
603 r_shadow_buffer_lighttrispvs = NULL;
605 r_shadow_usingdeferredprepass = false;
606 r_shadow_prepass_width = r_shadow_prepass_height = 0;
608 // determine renderpath specific capabilities, we don't need to figure
609 // these out per frame...
610 switch(vid.renderpath)
612 case RENDERPATH_GL20:
613 r_shadow_bouncegrid_state.allowdirectionalshading = true;
614 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
616 case RENDERPATH_GLES2:
617 // for performance reasons, do not use directional shading on GLES devices
618 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
623 static void R_Shadow_FreeDeferred(void);
624 static void r_shadow_shutdown(void)
627 R_Shadow_UncompileWorldLights();
629 R_Shadow_FreeShadowMaps();
631 r_shadow_usingdeferredprepass = false;
632 if (r_shadow_prepass_width)
633 R_Shadow_FreeDeferred();
634 r_shadow_prepass_width = r_shadow_prepass_height = 0;
637 r_shadow_scenemaxlights = 0;
638 r_shadow_scenenumlights = 0;
639 if (r_shadow_scenelightlist)
640 Mem_Free(r_shadow_scenelightlist);
641 r_shadow_scenelightlist = NULL;
642 r_shadow_bouncegrid_state.highpixels = NULL;
643 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
644 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
645 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
646 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
647 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
648 r_shadow_bouncegrid_state.maxsplatpaths = 0;
649 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
650 r_shadow_attenuationgradienttexture = NULL;
651 r_shadow_attenuation2dtexture = NULL;
652 r_shadow_attenuation3dtexture = NULL;
653 R_FreeTexturePool(&r_shadow_texturepool);
654 R_FreeTexturePool(&r_shadow_filters_texturepool);
655 maxshadowtriangles = 0;
657 Mem_Free(shadowelements);
658 shadowelements = NULL;
660 Mem_Free(shadowvertex3f);
661 shadowvertex3f = NULL;
664 Mem_Free(vertexupdate);
667 Mem_Free(vertexremap);
673 Mem_Free(shadowmark);
676 Mem_Free(shadowmarklist);
677 shadowmarklist = NULL;
682 Mem_Free(shadowsides);
685 Mem_Free(shadowsideslist);
686 shadowsideslist = NULL;
687 r_shadow_buffer_numleafpvsbytes = 0;
688 if (r_shadow_buffer_visitingleafpvs)
689 Mem_Free(r_shadow_buffer_visitingleafpvs);
690 r_shadow_buffer_visitingleafpvs = NULL;
691 if (r_shadow_buffer_leafpvs)
692 Mem_Free(r_shadow_buffer_leafpvs);
693 r_shadow_buffer_leafpvs = NULL;
694 if (r_shadow_buffer_leaflist)
695 Mem_Free(r_shadow_buffer_leaflist);
696 r_shadow_buffer_leaflist = NULL;
697 r_shadow_buffer_numsurfacepvsbytes = 0;
698 if (r_shadow_buffer_surfacepvs)
699 Mem_Free(r_shadow_buffer_surfacepvs);
700 r_shadow_buffer_surfacepvs = NULL;
701 if (r_shadow_buffer_surfacelist)
702 Mem_Free(r_shadow_buffer_surfacelist);
703 r_shadow_buffer_surfacelist = NULL;
704 if (r_shadow_buffer_surfacesides)
705 Mem_Free(r_shadow_buffer_surfacesides);
706 r_shadow_buffer_surfacesides = NULL;
707 r_shadow_buffer_numshadowtrispvsbytes = 0;
708 if (r_shadow_buffer_shadowtrispvs)
709 Mem_Free(r_shadow_buffer_shadowtrispvs);
710 r_shadow_buffer_numlighttrispvsbytes = 0;
711 if (r_shadow_buffer_lighttrispvs)
712 Mem_Free(r_shadow_buffer_lighttrispvs);
715 static void r_shadow_newmap(void)
717 r_shadow_bouncegrid_state.highpixels = NULL;
718 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
719 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
720 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
721 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
722 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
723 r_shadow_bouncegrid_state.maxsplatpaths = 0;
724 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
725 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
726 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
727 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
728 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
729 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
730 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
731 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
732 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
733 R_Shadow_EditLights_Reload_f();
736 void R_Shadow_Init(void)
738 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
739 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
740 Cvar_RegisterVariable(&r_shadow_usebihculling);
741 Cvar_RegisterVariable(&r_shadow_usenormalmap);
742 Cvar_RegisterVariable(&r_shadow_debuglight);
743 Cvar_RegisterVariable(&r_shadow_deferred);
744 Cvar_RegisterVariable(&r_shadow_gloss);
745 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
746 Cvar_RegisterVariable(&r_shadow_glossintensity);
747 Cvar_RegisterVariable(&r_shadow_glossexponent);
748 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
749 Cvar_RegisterVariable(&r_shadow_glossexact);
750 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
751 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
752 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
753 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
754 Cvar_RegisterVariable(&r_shadow_projectdistance);
755 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
756 Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
757 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
758 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
759 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
760 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
761 Cvar_RegisterVariable(&r_shadow_realtime_world);
762 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
763 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
764 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
765 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
766 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
767 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
768 Cvar_RegisterVariable(&r_shadow_scissor);
769 Cvar_RegisterVariable(&r_shadow_shadowmapping);
770 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
771 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
772 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
773 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
774 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
775 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
776 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
777 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturesize);
778 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
779 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
780 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
781 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
782 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
783 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
784 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
785 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
786 Cvar_RegisterVariable(&r_shadow_polygonfactor);
787 Cvar_RegisterVariable(&r_shadow_polygonoffset);
788 Cvar_RegisterVariable(&r_shadow_texture3d);
789 Cvar_RegisterVariable(&r_shadow_culllights_pvs);
790 Cvar_RegisterVariable(&r_shadow_culllights_trace);
791 Cvar_RegisterVariable(&r_shadow_culllights_trace_eyejitter);
792 Cvar_RegisterVariable(&r_shadow_culllights_trace_enlarge);
793 Cvar_RegisterVariable(&r_shadow_culllights_trace_expand);
794 Cvar_RegisterVariable(&r_shadow_culllights_trace_pad);
795 Cvar_RegisterVariable(&r_shadow_culllights_trace_samples);
796 Cvar_RegisterVariable(&r_shadow_culllights_trace_tempsamples);
797 Cvar_RegisterVariable(&r_shadow_culllights_trace_delay);
798 Cvar_RegisterVariable(&r_shadow_bouncegrid);
799 Cvar_RegisterVariable(&r_shadow_bouncegrid_blur);
800 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
801 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_bounceminimumintensity);
802 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_culllightpaths);
803 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_directionalshading);
804 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_dlightparticlemultiplier);
805 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_hitmodels);
806 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_lightradiusscale);
807 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxbounce);
808 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxphotons);
809 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_quality);
810 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_spacing);
811 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_updateinterval);
812 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_x);
813 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_y);
814 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_z);
815 Cvar_RegisterVariable(&r_shadow_bouncegrid_floatcolors);
816 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
817 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
818 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize_conespread);
819 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize_initial);
820 Cvar_RegisterVariable(&r_shadow_bouncegrid_normalizevectors);
821 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
822 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
823 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_seed);
824 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_type);
825 Cvar_RegisterVariable(&r_shadow_bouncegrid_sortlightpaths);
826 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
827 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_bounceminimumintensity);
828 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
829 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
830 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
831 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxphotons);
832 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_quality);
833 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_spacing);
834 Cvar_RegisterVariable(&r_coronas);
835 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
836 Cvar_RegisterVariable(&r_coronas_occlusionquery);
837 Cvar_RegisterVariable(&gl_flashblend);
838 Cvar_RegisterVariable(&gl_ext_separatestencil);
839 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
840 R_Shadow_EditLights_Init();
841 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
842 r_shadow_scenemaxlights = 0;
843 r_shadow_scenenumlights = 0;
844 r_shadow_scenelightlist = NULL;
845 maxshadowtriangles = 0;
846 shadowelements = NULL;
847 maxshadowvertices = 0;
848 shadowvertex3f = NULL;
856 shadowmarklist = NULL;
861 shadowsideslist = NULL;
862 r_shadow_buffer_numleafpvsbytes = 0;
863 r_shadow_buffer_visitingleafpvs = NULL;
864 r_shadow_buffer_leafpvs = NULL;
865 r_shadow_buffer_leaflist = NULL;
866 r_shadow_buffer_numsurfacepvsbytes = 0;
867 r_shadow_buffer_surfacepvs = NULL;
868 r_shadow_buffer_surfacelist = NULL;
869 r_shadow_buffer_surfacesides = NULL;
870 r_shadow_buffer_shadowtrispvs = NULL;
871 r_shadow_buffer_lighttrispvs = NULL;
872 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
875 matrix4x4_t matrix_attenuationxyz =
878 {0.5, 0.0, 0.0, 0.5},
879 {0.0, 0.5, 0.0, 0.5},
880 {0.0, 0.0, 0.5, 0.5},
885 matrix4x4_t matrix_attenuationz =
888 {0.0, 0.0, 0.5, 0.5},
889 {0.0, 0.0, 0.0, 0.5},
890 {0.0, 0.0, 0.0, 0.5},
895 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
897 numvertices = ((numvertices + 255) & ~255) * vertscale;
898 numtriangles = ((numtriangles + 255) & ~255) * triscale;
899 // make sure shadowelements is big enough for this volume
900 if (maxshadowtriangles < numtriangles)
902 maxshadowtriangles = numtriangles;
904 Mem_Free(shadowelements);
905 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
907 // make sure shadowvertex3f is big enough for this volume
908 if (maxshadowvertices < numvertices)
910 maxshadowvertices = numvertices;
912 Mem_Free(shadowvertex3f);
913 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
917 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
919 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
920 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
921 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
922 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
923 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
925 if (r_shadow_buffer_visitingleafpvs)
926 Mem_Free(r_shadow_buffer_visitingleafpvs);
927 if (r_shadow_buffer_leafpvs)
928 Mem_Free(r_shadow_buffer_leafpvs);
929 if (r_shadow_buffer_leaflist)
930 Mem_Free(r_shadow_buffer_leaflist);
931 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
932 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
933 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
934 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
936 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
938 if (r_shadow_buffer_surfacepvs)
939 Mem_Free(r_shadow_buffer_surfacepvs);
940 if (r_shadow_buffer_surfacelist)
941 Mem_Free(r_shadow_buffer_surfacelist);
942 if (r_shadow_buffer_surfacesides)
943 Mem_Free(r_shadow_buffer_surfacesides);
944 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
945 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
946 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
947 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
949 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
951 if (r_shadow_buffer_shadowtrispvs)
952 Mem_Free(r_shadow_buffer_shadowtrispvs);
953 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
954 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
956 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
958 if (r_shadow_buffer_lighttrispvs)
959 Mem_Free(r_shadow_buffer_lighttrispvs);
960 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
961 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
965 void R_Shadow_PrepareShadowMark(int numtris)
967 // make sure shadowmark is big enough for this volume
968 if (maxshadowmark < numtris)
970 maxshadowmark = numtris;
972 Mem_Free(shadowmark);
974 Mem_Free(shadowmarklist);
975 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
976 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
980 // if shadowmarkcount wrapped we clear the array and adjust accordingly
981 if (shadowmarkcount == 0)
984 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
989 void R_Shadow_PrepareShadowSides(int numtris)
991 if (maxshadowsides < numtris)
993 maxshadowsides = numtris;
995 Mem_Free(shadowsides);
997 Mem_Free(shadowsideslist);
998 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
999 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
1004 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)
1007 int outtriangles = 0, outvertices = 0;
1009 const float *vertex;
1010 float ratio, direction[3], projectvector[3];
1012 if (projectdirection)
1013 VectorScale(projectdirection, projectdistance, projectvector);
1015 VectorClear(projectvector);
1017 // create the vertices
1018 if (projectdirection)
1020 for (i = 0;i < numshadowmarktris;i++)
1022 element = inelement3i + shadowmarktris[i] * 3;
1023 for (j = 0;j < 3;j++)
1025 if (vertexupdate[element[j]] != vertexupdatenum)
1027 vertexupdate[element[j]] = vertexupdatenum;
1028 vertexremap[element[j]] = outvertices;
1029 vertex = invertex3f + element[j] * 3;
1030 // project one copy of the vertex according to projectvector
1031 VectorCopy(vertex, outvertex3f);
1032 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1041 for (i = 0;i < numshadowmarktris;i++)
1043 element = inelement3i + shadowmarktris[i] * 3;
1044 for (j = 0;j < 3;j++)
1046 if (vertexupdate[element[j]] != vertexupdatenum)
1048 vertexupdate[element[j]] = vertexupdatenum;
1049 vertexremap[element[j]] = outvertices;
1050 vertex = invertex3f + element[j] * 3;
1051 // project one copy of the vertex to the sphere radius of the light
1052 // (FIXME: would projecting it to the light box be better?)
1053 VectorSubtract(vertex, projectorigin, direction);
1054 ratio = projectdistance / VectorLength(direction);
1055 VectorCopy(vertex, outvertex3f);
1056 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1064 if (r_shadow_frontsidecasting.integer)
1066 for (i = 0;i < numshadowmarktris;i++)
1068 int remappedelement[3];
1070 const int *neighbortriangle;
1072 markindex = shadowmarktris[i] * 3;
1073 element = inelement3i + markindex;
1074 neighbortriangle = inneighbor3i + markindex;
1075 // output the front and back triangles
1076 outelement3i[0] = vertexremap[element[0]];
1077 outelement3i[1] = vertexremap[element[1]];
1078 outelement3i[2] = vertexremap[element[2]];
1079 outelement3i[3] = vertexremap[element[2]] + 1;
1080 outelement3i[4] = vertexremap[element[1]] + 1;
1081 outelement3i[5] = vertexremap[element[0]] + 1;
1085 // output the sides (facing outward from this triangle)
1086 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1088 remappedelement[0] = vertexremap[element[0]];
1089 remappedelement[1] = vertexremap[element[1]];
1090 outelement3i[0] = remappedelement[1];
1091 outelement3i[1] = remappedelement[0];
1092 outelement3i[2] = remappedelement[0] + 1;
1093 outelement3i[3] = remappedelement[1];
1094 outelement3i[4] = remappedelement[0] + 1;
1095 outelement3i[5] = remappedelement[1] + 1;
1100 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1102 remappedelement[1] = vertexremap[element[1]];
1103 remappedelement[2] = vertexremap[element[2]];
1104 outelement3i[0] = remappedelement[2];
1105 outelement3i[1] = remappedelement[1];
1106 outelement3i[2] = remappedelement[1] + 1;
1107 outelement3i[3] = remappedelement[2];
1108 outelement3i[4] = remappedelement[1] + 1;
1109 outelement3i[5] = remappedelement[2] + 1;
1114 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1116 remappedelement[0] = vertexremap[element[0]];
1117 remappedelement[2] = vertexremap[element[2]];
1118 outelement3i[0] = remappedelement[0];
1119 outelement3i[1] = remappedelement[2];
1120 outelement3i[2] = remappedelement[2] + 1;
1121 outelement3i[3] = remappedelement[0];
1122 outelement3i[4] = remappedelement[2] + 1;
1123 outelement3i[5] = remappedelement[0] + 1;
1132 for (i = 0;i < numshadowmarktris;i++)
1134 int remappedelement[3];
1136 const int *neighbortriangle;
1138 markindex = shadowmarktris[i] * 3;
1139 element = inelement3i + markindex;
1140 neighbortriangle = inneighbor3i + markindex;
1141 // output the front and back triangles
1142 outelement3i[0] = vertexremap[element[2]];
1143 outelement3i[1] = vertexremap[element[1]];
1144 outelement3i[2] = vertexremap[element[0]];
1145 outelement3i[3] = vertexremap[element[0]] + 1;
1146 outelement3i[4] = vertexremap[element[1]] + 1;
1147 outelement3i[5] = vertexremap[element[2]] + 1;
1151 // output the sides (facing outward from this triangle)
1152 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1154 remappedelement[0] = vertexremap[element[0]];
1155 remappedelement[1] = vertexremap[element[1]];
1156 outelement3i[0] = remappedelement[0];
1157 outelement3i[1] = remappedelement[1];
1158 outelement3i[2] = remappedelement[1] + 1;
1159 outelement3i[3] = remappedelement[0];
1160 outelement3i[4] = remappedelement[1] + 1;
1161 outelement3i[5] = remappedelement[0] + 1;
1166 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1168 remappedelement[1] = vertexremap[element[1]];
1169 remappedelement[2] = vertexremap[element[2]];
1170 outelement3i[0] = remappedelement[1];
1171 outelement3i[1] = remappedelement[2];
1172 outelement3i[2] = remappedelement[2] + 1;
1173 outelement3i[3] = remappedelement[1];
1174 outelement3i[4] = remappedelement[2] + 1;
1175 outelement3i[5] = remappedelement[1] + 1;
1180 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1182 remappedelement[0] = vertexremap[element[0]];
1183 remappedelement[2] = vertexremap[element[2]];
1184 outelement3i[0] = remappedelement[2];
1185 outelement3i[1] = remappedelement[0];
1186 outelement3i[2] = remappedelement[0] + 1;
1187 outelement3i[3] = remappedelement[2];
1188 outelement3i[4] = remappedelement[0] + 1;
1189 outelement3i[5] = remappedelement[2] + 1;
1197 *outnumvertices = outvertices;
1198 return outtriangles;
1201 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)
1204 int outtriangles = 0, outvertices = 0;
1206 const float *vertex;
1207 float ratio, direction[3], projectvector[3];
1210 if (projectdirection)
1211 VectorScale(projectdirection, projectdistance, projectvector);
1213 VectorClear(projectvector);
1215 for (i = 0;i < numshadowmarktris;i++)
1217 int remappedelement[3];
1219 const int *neighbortriangle;
1221 markindex = shadowmarktris[i] * 3;
1222 neighbortriangle = inneighbor3i + markindex;
1223 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1224 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1225 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1226 if (side[0] + side[1] + side[2] == 0)
1230 element = inelement3i + markindex;
1232 // create the vertices
1233 for (j = 0;j < 3;j++)
1235 if (side[j] + side[j+1] == 0)
1238 if (vertexupdate[k] != vertexupdatenum)
1240 vertexupdate[k] = vertexupdatenum;
1241 vertexremap[k] = outvertices;
1242 vertex = invertex3f + k * 3;
1243 VectorCopy(vertex, outvertex3f);
1244 if (projectdirection)
1246 // project one copy of the vertex according to projectvector
1247 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1251 // project one copy of the vertex to the sphere radius of the light
1252 // (FIXME: would projecting it to the light box be better?)
1253 VectorSubtract(vertex, projectorigin, direction);
1254 ratio = projectdistance / VectorLength(direction);
1255 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1262 // output the sides (facing outward from this triangle)
1265 remappedelement[0] = vertexremap[element[0]];
1266 remappedelement[1] = vertexremap[element[1]];
1267 outelement3i[0] = remappedelement[1];
1268 outelement3i[1] = remappedelement[0];
1269 outelement3i[2] = remappedelement[0] + 1;
1270 outelement3i[3] = remappedelement[1];
1271 outelement3i[4] = remappedelement[0] + 1;
1272 outelement3i[5] = remappedelement[1] + 1;
1279 remappedelement[1] = vertexremap[element[1]];
1280 remappedelement[2] = vertexremap[element[2]];
1281 outelement3i[0] = remappedelement[2];
1282 outelement3i[1] = remappedelement[1];
1283 outelement3i[2] = remappedelement[1] + 1;
1284 outelement3i[3] = remappedelement[2];
1285 outelement3i[4] = remappedelement[1] + 1;
1286 outelement3i[5] = remappedelement[2] + 1;
1293 remappedelement[0] = vertexremap[element[0]];
1294 remappedelement[2] = vertexremap[element[2]];
1295 outelement3i[0] = remappedelement[0];
1296 outelement3i[1] = remappedelement[2];
1297 outelement3i[2] = remappedelement[2] + 1;
1298 outelement3i[3] = remappedelement[0];
1299 outelement3i[4] = remappedelement[2] + 1;
1300 outelement3i[5] = remappedelement[0] + 1;
1307 *outnumvertices = outvertices;
1308 return outtriangles;
1311 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)
1317 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1319 tend = firsttriangle + numtris;
1320 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1322 // surface box entirely inside light box, no box cull
1323 if (projectdirection)
1325 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1327 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1328 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1329 shadowmarklist[numshadowmark++] = t;
1334 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1335 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1336 shadowmarklist[numshadowmark++] = t;
1341 // surface box not entirely inside light box, cull each triangle
1342 if (projectdirection)
1344 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1346 v[0] = invertex3f + e[0] * 3;
1347 v[1] = invertex3f + e[1] * 3;
1348 v[2] = invertex3f + e[2] * 3;
1349 TriangleNormal(v[0], v[1], v[2], normal);
1350 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1351 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1352 shadowmarklist[numshadowmark++] = t;
1357 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1359 v[0] = invertex3f + e[0] * 3;
1360 v[1] = invertex3f + e[1] * 3;
1361 v[2] = invertex3f + e[2] * 3;
1362 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1363 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1364 shadowmarklist[numshadowmark++] = t;
1370 static qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1375 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1377 // check if the shadow volume intersects the near plane
1379 // a ray between the eye and light origin may intersect the caster,
1380 // indicating that the shadow may touch the eye location, however we must
1381 // test the near plane (a polygon), not merely the eye location, so it is
1382 // easiest to enlarge the caster bounding shape slightly for this.
1388 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)
1390 int i, tris, outverts;
1391 if (projectdistance < 0.1)
1393 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1396 if (!numverts || !nummarktris)
1398 // make sure shadowelements is big enough for this volume
1399 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1400 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1402 if (maxvertexupdate < numverts)
1404 maxvertexupdate = numverts;
1406 Mem_Free(vertexupdate);
1408 Mem_Free(vertexremap);
1409 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1410 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1411 vertexupdatenum = 0;
1414 if (vertexupdatenum == 0)
1416 vertexupdatenum = 1;
1417 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1418 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1421 for (i = 0;i < nummarktris;i++)
1422 shadowmark[marktris[i]] = shadowmarkcount;
1424 if (r_shadow_compilingrtlight)
1426 // if we're compiling an rtlight, capture the mesh
1427 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1428 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1429 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1430 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1432 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1434 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1435 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1436 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1440 // decide which type of shadow to generate and set stencil mode
1441 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1442 // generate the sides or a solid volume, depending on type
1443 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1444 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1446 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1447 r_refdef.stats[r_stat_lights_dynamicshadowtriangles] += tris;
1448 r_refdef.stats[r_stat_lights_shadowtriangles] += tris;
1449 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1451 // increment stencil if frontface is infront of depthbuffer
1452 GL_CullFace(r_refdef.view.cullface_front);
1453 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1454 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1455 // decrement stencil if backface is infront of depthbuffer
1456 GL_CullFace(r_refdef.view.cullface_back);
1457 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1459 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1461 // decrement stencil if backface is behind depthbuffer
1462 GL_CullFace(r_refdef.view.cullface_front);
1463 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1464 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1465 // increment stencil if frontface is behind depthbuffer
1466 GL_CullFace(r_refdef.view.cullface_back);
1467 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1469 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1470 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1474 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1476 // p1, p2, p3 are in the cubemap's local coordinate system
1477 // bias = border/(size - border)
1480 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1481 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1482 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1483 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1485 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1486 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1487 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1488 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1490 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1491 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1492 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1494 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1495 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1496 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1497 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1499 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1500 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1501 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1502 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1504 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1505 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1506 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1508 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1509 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1510 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1511 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1513 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1514 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1515 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1516 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1518 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1519 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1520 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1525 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1527 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1528 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1531 VectorSubtract(maxs, mins, radius);
1532 VectorScale(radius, 0.5f, radius);
1533 VectorAdd(mins, radius, center);
1534 Matrix4x4_Transform(worldtolight, center, lightcenter);
1535 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1536 VectorSubtract(lightcenter, lightradius, pmin);
1537 VectorAdd(lightcenter, lightradius, pmax);
1539 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1540 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1541 if(ap1 > bias*an1 && ap2 > bias*an2)
1543 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1544 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1545 if(an1 > bias*ap1 && an2 > bias*ap2)
1547 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1548 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1550 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1551 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1552 if(ap1 > bias*an1 && ap2 > bias*an2)
1554 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1555 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1556 if(an1 > bias*ap1 && an2 > bias*ap2)
1558 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1559 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1561 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1562 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1563 if(ap1 > bias*an1 && ap2 > bias*an2)
1565 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1566 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1567 if(an1 > bias*ap1 && an2 > bias*ap2)
1569 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1570 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1575 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1577 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1579 // p is in the cubemap's local coordinate system
1580 // bias = border/(size - border)
1581 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1582 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1583 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1585 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1586 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1587 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1588 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1589 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1590 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1594 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1598 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1599 float scale = (size - 2*border)/size, len;
1600 float bias = border / (float)(size - border), dp, dn, ap, an;
1601 // check if cone enclosing side would cross frustum plane
1602 scale = 2 / (scale*scale + 2);
1603 Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
1604 for (i = 0;i < 5;i++)
1606 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
1608 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1609 len = scale*VectorLength2(n);
1610 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1611 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1612 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1614 if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1616 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1617 len = scale*VectorLength2(n);
1618 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1619 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1620 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1622 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1623 // check if frustum corners/origin cross plane sides
1625 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1626 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1627 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1628 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1629 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1630 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1631 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1632 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1633 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1634 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1635 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1636 for (i = 0;i < 4;i++)
1638 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1639 VectorSubtract(n, p, n);
1640 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1641 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1642 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1643 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1644 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1645 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1646 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1647 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1648 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1651 // finite version, assumes corners are a finite distance from origin dependent on far plane
1652 for (i = 0;i < 5;i++)
1654 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1655 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1656 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1657 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1658 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1659 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1660 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1661 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1662 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1663 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1666 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1669 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)
1677 int mask, surfacemask = 0;
1678 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1680 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1681 tend = firsttriangle + numtris;
1682 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1684 // surface box entirely inside light box, no box cull
1685 if (projectdirection)
1687 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1689 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1690 TriangleNormal(v[0], v[1], v[2], normal);
1691 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1693 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1694 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1695 surfacemask |= mask;
1698 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;
1699 shadowsides[numshadowsides] = mask;
1700 shadowsideslist[numshadowsides++] = t;
1707 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1709 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1710 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1712 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1713 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1714 surfacemask |= mask;
1717 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;
1718 shadowsides[numshadowsides] = mask;
1719 shadowsideslist[numshadowsides++] = t;
1727 // surface box not entirely inside light box, cull each triangle
1728 if (projectdirection)
1730 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1732 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1733 TriangleNormal(v[0], v[1], v[2], normal);
1734 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1735 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1737 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1738 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1739 surfacemask |= mask;
1742 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1743 shadowsides[numshadowsides] = mask;
1744 shadowsideslist[numshadowsides++] = t;
1751 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1753 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1754 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1755 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1757 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1758 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1759 surfacemask |= mask;
1762 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;
1763 shadowsides[numshadowsides] = mask;
1764 shadowsideslist[numshadowsides++] = t;
1773 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)
1775 int i, j, outtriangles = 0;
1776 int *outelement3i[6];
1777 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1779 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1780 // make sure shadowelements is big enough for this mesh
1781 if (maxshadowtriangles < outtriangles)
1782 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1784 // compute the offset and size of the separate index lists for each cubemap side
1786 for (i = 0;i < 6;i++)
1788 outelement3i[i] = shadowelements + outtriangles * 3;
1789 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1790 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1791 outtriangles += sidetotals[i];
1794 // gather up the (sparse) triangles into separate index lists for each cubemap side
1795 for (i = 0;i < numsidetris;i++)
1797 const int *element = elements + sidetris[i] * 3;
1798 for (j = 0;j < 6;j++)
1800 if (sides[i] & (1 << j))
1802 outelement3i[j][0] = element[0];
1803 outelement3i[j][1] = element[1];
1804 outelement3i[j][2] = element[2];
1805 outelement3i[j] += 3;
1810 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1813 static void R_Shadow_MakeTextures_MakeCorona(void)
1817 unsigned char pixels[32][32][4];
1818 for (y = 0;y < 32;y++)
1820 dy = (y - 15.5f) * (1.0f / 16.0f);
1821 for (x = 0;x < 32;x++)
1823 dx = (x - 15.5f) * (1.0f / 16.0f);
1824 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1825 a = bound(0, a, 255);
1826 pixels[y][x][0] = a;
1827 pixels[y][x][1] = a;
1828 pixels[y][x][2] = a;
1829 pixels[y][x][3] = 255;
1832 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, false);
1835 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1837 float dist = sqrt(x*x+y*y+z*z);
1838 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1839 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1840 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1843 static void R_Shadow_MakeTextures(void)
1846 float intensity, dist;
1848 R_Shadow_FreeShadowMaps();
1849 R_FreeTexturePool(&r_shadow_texturepool);
1850 r_shadow_texturepool = R_AllocTexturePool();
1851 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1852 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1853 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1854 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1855 for (x = 0;x <= ATTENTABLESIZE;x++)
1857 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1858 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1859 r_shadow_attentable[x] = bound(0, intensity, 1);
1861 // 1D gradient texture
1862 for (x = 0;x < ATTEN1DSIZE;x++)
1863 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1864 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1865 // 2D circle texture
1866 for (y = 0;y < ATTEN2DSIZE;y++)
1867 for (x = 0;x < ATTEN2DSIZE;x++)
1868 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);
1869 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1870 // 3D sphere texture
1871 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1873 for (z = 0;z < ATTEN3DSIZE;z++)
1874 for (y = 0;y < ATTEN3DSIZE;y++)
1875 for (x = 0;x < ATTEN3DSIZE;x++)
1876 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));
1877 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);
1880 r_shadow_attenuation3dtexture = NULL;
1883 R_Shadow_MakeTextures_MakeCorona();
1885 // Editor light sprites
1886 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1903 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1904 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1921 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1922 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1939 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1940 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1957 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1958 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1975 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1976 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1993 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1996 void R_Shadow_ValidateCvars(void)
1998 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1999 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
2000 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
2001 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
2002 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
2003 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
2006 void R_Shadow_RenderMode_Begin(void)
2012 R_Shadow_ValidateCvars();
2014 if (!r_shadow_attenuation2dtexture
2015 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
2016 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
2017 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
2018 R_Shadow_MakeTextures();
2021 R_Mesh_ResetTextureState();
2022 GL_BlendFunc(GL_ONE, GL_ZERO);
2023 GL_DepthRange(0, 1);
2024 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
2026 GL_DepthMask(false);
2027 GL_Color(0, 0, 0, 1);
2028 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2030 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2032 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
2034 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
2035 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
2037 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
2039 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
2040 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
2044 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
2045 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
2048 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
2052 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
2053 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
2054 r_shadow_drawbuffer = drawbuffer;
2055 r_shadow_readbuffer = readbuffer;
2057 r_shadow_cullface_front = r_refdef.view.cullface_front;
2058 r_shadow_cullface_back = r_refdef.view.cullface_back;
2061 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
2063 rsurface.rtlight = rtlight;
2066 void R_Shadow_RenderMode_Reset(void)
2068 R_Mesh_ResetTextureState();
2069 R_Mesh_SetRenderTargets(r_shadow_viewfbo, r_shadow_viewdepthtexture, r_shadow_viewcolortexture, NULL, NULL, NULL);
2070 R_SetViewport(&r_refdef.view.viewport);
2071 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
2072 GL_DepthRange(0, 1);
2074 GL_DepthMask(false);
2075 GL_DepthFunc(GL_LEQUAL);
2076 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2077 r_refdef.view.cullface_front = r_shadow_cullface_front;
2078 r_refdef.view.cullface_back = r_shadow_cullface_back;
2079 GL_CullFace(r_refdef.view.cullface_back);
2080 GL_Color(1, 1, 1, 1);
2081 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2082 GL_BlendFunc(GL_ONE, GL_ZERO);
2083 R_SetupShader_Generic_NoTexture(false, false);
2084 r_shadow_usingshadowmap2d = false;
2085 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2088 void R_Shadow_ClearStencil(void)
2090 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2091 r_refdef.stats[r_stat_lights_clears]++;
2094 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2096 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2097 if (r_shadow_rendermode == mode)
2099 R_Shadow_RenderMode_Reset();
2100 GL_DepthFunc(GL_LESS);
2101 GL_ColorMask(0, 0, 0, 0);
2102 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2103 GL_CullFace(GL_NONE);
2104 R_SetupShader_DepthOrShadow(false, false, false); // FIXME test if we have a skeletal model?
2105 r_shadow_rendermode = mode;
2110 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2111 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2112 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2114 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2115 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2116 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2121 static void R_Shadow_MakeVSDCT(void)
2123 // maps to a 2x3 texture rectangle with normalized coordinates
2128 // stores abs(dir.xy), offset.xy/2.5
2129 unsigned char data[4*6] =
2131 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2132 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2133 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2134 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2135 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2136 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2138 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2141 static void R_Shadow_MakeShadowMap(int texturesize)
2143 switch (r_shadow_shadowmode)
2145 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2146 if (r_shadow_shadowmap2ddepthtexture) return;
2147 if (r_fb.usedepthtextures)
2149 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);
2150 r_shadow_shadowmap2ddepthbuffer = NULL;
2151 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2155 r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", texturesize, texturesize, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2156 r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
2157 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2165 void R_Shadow_ClearShadowMapTexture(void)
2167 r_viewport_t viewport;
2168 float clearcolor[4];
2170 // if they don't exist, create our textures now
2171 if (!r_shadow_shadowmap2ddepthtexture)
2172 R_Shadow_MakeShadowMap(r_shadow_shadowmaptexturesize);
2173 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2174 R_Shadow_MakeVSDCT();
2176 // we're setting up to render shadowmaps, so change rendermode
2177 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2179 R_Mesh_ResetTextureState();
2180 R_Shadow_RenderMode_Reset();
2181 if (r_shadow_shadowmap2ddepthbuffer)
2182 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2184 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2185 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2186 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2190 // we have to set a viewport to clear anything in some renderpaths (D3D)
2191 R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize, 0, 0, 1.0, 1.0, 0.001f, 1.0f, NULL);
2192 R_SetViewport(&viewport);
2193 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2194 if (r_shadow_shadowmap2ddepthbuffer)
2195 GL_ColorMask(1, 1, 1, 1);
2197 GL_ColorMask(0, 0, 0, 0);
2198 switch (vid.renderpath)
2200 case RENDERPATH_GL20:
2201 case RENDERPATH_GLES2:
2202 GL_CullFace(r_refdef.view.cullface_back);
2205 Vector4Set(clearcolor, 1, 1, 1, 1);
2206 if (r_shadow_shadowmap2ddepthbuffer)
2207 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2209 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2212 static void R_Shadow_SetShadowmapParametersForLight(qboolean noselfshadowpass)
2214 int size = rsurface.rtlight->shadowmapatlassidesize;
2215 float nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2216 float farclip = 1.0f;
2217 float bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2218 r_shadow_lightshadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
2219 r_shadow_lightshadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
2220 r_shadow_lightshadowmap_texturescale[2] = rsurface.rtlight->shadowmapatlasposition[0] + (noselfshadowpass ? size * 2 : 0);
2221 r_shadow_lightshadowmap_texturescale[3] = rsurface.rtlight->shadowmapatlasposition[1];
2222 r_shadow_lightshadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2223 r_shadow_lightshadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2224 r_shadow_lightshadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2225 r_shadow_lightshadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2226 if (r_shadow_shadowmap2ddepthbuffer)
2228 // completely different meaning than in depthtexture approach
2229 r_shadow_lightshadowmap_parameters[1] = 0;
2230 r_shadow_lightshadowmap_parameters[3] = -bias;
2234 static void R_Shadow_RenderMode_ShadowMap(int side, int size, int x, int y)
2236 float nearclip, farclip, bias;
2237 r_viewport_t viewport;
2239 float clearcolor[4];
2241 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_SHADOWMAP2D)
2243 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2245 R_Mesh_ResetTextureState();
2246 R_Shadow_RenderMode_Reset();
2247 if (r_shadow_shadowmap2ddepthbuffer)
2248 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2250 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2251 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2252 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2257 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2259 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2261 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
2262 R_SetViewport(&viewport);
2263 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2264 flipped = (side & 1) ^ (side >> 2);
2265 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2266 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2268 Vector4Set(clearcolor, 1,1,1,1);
2269 if (r_shadow_shadowmap2ddepthbuffer)
2270 GL_ColorMask(1,1,1,1);
2272 GL_ColorMask(0,0,0,0);
2273 switch(vid.renderpath)
2275 case RENDERPATH_GL20:
2276 case RENDERPATH_GLES2:
2277 GL_CullFace(r_refdef.view.cullface_back);
2281 // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
2282 r_shadow_shadowmapside = side;
2285 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass)
2287 R_Mesh_ResetTextureState();
2290 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2291 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2292 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2293 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2296 R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
2297 R_Shadow_RenderMode_Reset();
2298 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2300 GL_DepthFunc(GL_EQUAL);
2301 // do global setup needed for the chosen lighting mode
2302 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2303 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2304 r_shadow_usingshadowmap2d = shadowmapping;
2305 r_shadow_rendermode = r_shadow_lightingrendermode;
2306 // only draw light where this geometry was already rendered AND the
2307 // stencil is 128 (values other than this mean shadow)
2309 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2311 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2314 static const unsigned short bboxelements[36] =
2324 static const float bboxpoints[8][3] =
2336 void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping)
2339 float vertex3f[8*3];
2340 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2341 // do global setup needed for the chosen lighting mode
2342 R_Shadow_RenderMode_Reset();
2343 r_shadow_rendermode = r_shadow_lightingrendermode;
2344 R_EntityMatrix(&identitymatrix);
2345 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2346 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2347 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
2348 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2350 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
2352 r_shadow_usingshadowmap2d = shadowmapping;
2354 // render the lighting
2355 R_SetupShader_DeferredLight(rsurface.rtlight);
2356 for (i = 0;i < 8;i++)
2357 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2358 GL_ColorMask(1,1,1,1);
2359 GL_DepthMask(false);
2360 GL_DepthRange(0, 1);
2361 GL_PolygonOffset(0, 0);
2363 GL_DepthFunc(GL_GREATER);
2364 GL_CullFace(r_refdef.view.cullface_back);
2365 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
2366 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2369 #define MAXBOUNCEGRIDSPLATSIZE 7
2370 #define MAXBOUNCEGRIDSPLATSIZE1 (MAXBOUNCEGRIDSPLATSIZE+1)
2372 // these are temporary data per-frame, sorted and performed in a more
2373 // cache-friendly order than the original photons
2374 typedef struct r_shadow_bouncegrid_splatpath_s
2380 vec_t splatintensity;
2381 vec_t splatsize_current;
2382 vec_t splatsize_perstep;
2383 int remainingsplats;
2385 r_shadow_bouncegrid_splatpath_t;
2387 static void R_Shadow_BounceGrid_AddSplatPath(vec3_t originalstart, vec3_t originalend, vec3_t color, vec_t distancetraveled)
2397 r_shadow_bouncegrid_splatpath_t *path;
2399 // cull paths that fail R_CullBox in dynamic mode
2400 if (!r_shadow_bouncegrid_state.settings.staticmode
2401 && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
2403 vec3_t cullmins, cullmaxs;
2404 cullmins[0] = min(originalstart[0], originalend[0]) - r_shadow_bouncegrid_state.settings.spacing[0];
2405 cullmins[1] = min(originalstart[1], originalend[1]) - r_shadow_bouncegrid_state.settings.spacing[1];
2406 cullmins[2] = min(originalstart[2], originalend[2]) - r_shadow_bouncegrid_state.settings.spacing[2];
2407 cullmaxs[0] = max(originalstart[0], originalend[0]) + r_shadow_bouncegrid_state.settings.spacing[0];
2408 cullmaxs[1] = max(originalstart[1], originalend[1]) + r_shadow_bouncegrid_state.settings.spacing[1];
2409 cullmaxs[2] = max(originalstart[2], originalend[2]) + r_shadow_bouncegrid_state.settings.spacing[2];
2410 if (R_CullBox(cullmins, cullmaxs))
2414 // if the light path is going upward, reverse it - we always draw down.
2415 if (originalend[2] < originalstart[2])
2417 VectorCopy(originalend, start);
2418 VectorCopy(originalstart, end);
2422 VectorCopy(originalstart, start);
2423 VectorCopy(originalend, end);
2426 // transform to texture pixels
2427 start[0] = (start[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2428 start[1] = (start[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2429 start[2] = (start[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2430 end[0] = (end[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2431 end[1] = (end[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2432 end[2] = (end[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2434 // check if we need to grow the splatpaths array
2435 if (r_shadow_bouncegrid_state.maxsplatpaths <= r_shadow_bouncegrid_state.numsplatpaths)
2437 // double the limit, this will persist from frame to frame so we don't
2438 // make the same mistake each time
2439 r_shadow_bouncegrid_state.maxsplatpaths *= 2;
2440 if (r_shadow_bouncegrid_state.maxsplatpaths < 16384)
2441 r_shadow_bouncegrid_state.maxsplatpaths = 16384;
2442 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);
2445 // divide a series of splats along the length using the maximum axis
2446 VectorSubtract(end, start, diff);
2447 // pick the best axis to trace along
2449 if (diff[1]*diff[1] > diff[bestaxis]*diff[bestaxis])
2451 if (diff[2]*diff[2] > diff[bestaxis]*diff[bestaxis])
2453 len = fabs(diff[bestaxis]);
2455 numsplats = (int)(floor(len + 0.5f));
2457 numsplats = bound(0, numsplats, 1024);
2459 VectorSubtract(originalstart, originalend, originaldir);
2460 VectorNormalize(originaldir);
2462 path = r_shadow_bouncegrid_state.splatpaths + r_shadow_bouncegrid_state.numsplatpaths++;
2463 VectorCopy(start, path->point);
2464 VectorScale(diff, ilen, path->step);
2465 VectorCopy(color, path->splatcolor);
2466 VectorCopy(originaldir, path->splatdir);
2467 path->splatsize_current = r_shadow_bouncegrid_state.settings.lightpathsize_initial + r_shadow_bouncegrid_state.settings.lightpathsize_conespread * distancetraveled * r_shadow_bouncegrid_state.ispacing[0];
2468 path->splatsize_perstep = r_shadow_bouncegrid_state.settings.lightpathsize_conespread;
2469 path->splatintensity = VectorLength(color);
2470 path->remainingsplats = numsplats;
2473 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
2475 qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
2482 // see if there are really any lights to render...
2483 if (enable && r_shadow_bouncegrid_static.integer)
2486 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2487 for (lightindex = 0;lightindex < range;lightindex++)
2489 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2490 if (!light || !(light->flags & flag))
2492 rtlight = &light->rtlight;
2493 // when static, we skip styled lights because they tend to change...
2494 if (rtlight->style > 0)
2496 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
2497 if (!VectorLength2(lightcolor))
2507 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
2509 qboolean s = r_shadow_bouncegrid_static.integer != 0;
2510 float spacing = bound(1.0f, s ? r_shadow_bouncegrid_static_spacing.value : r_shadow_bouncegrid_dynamic_spacing.value, 1024.0f);
2511 float quality = bound(0.0001f, (s ? r_shadow_bouncegrid_static_quality.value : r_shadow_bouncegrid_dynamic_quality.value), 1024.0f);
2512 float bounceminimumintensity = s ? r_shadow_bouncegrid_static_bounceminimumintensity.value : r_shadow_bouncegrid_dynamic_bounceminimumintensity.value;
2514 // prevent any garbage in alignment padded areas as we'll be using memcmp
2515 memset(settings, 0, sizeof(*settings));
2517 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
2518 settings->staticmode = s;
2519 settings->blur = r_shadow_bouncegrid_blur.integer != 0;
2520 settings->floatcolors = bound(0, r_shadow_bouncegrid_floatcolors.integer, 2);
2521 settings->lightpathsize_initial = bound(0.0f, r_shadow_bouncegrid_lightpathsize_initial.value, 1024.0f);
2522 settings->lightpathsize_conespread = bound(0.0f, r_shadow_bouncegrid_lightpathsize_conespread.value, 1024.0f);
2523 settings->bounceanglediffuse = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
2524 settings->directionalshading = (s ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_dynamic_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
2525 settings->dlightparticlemultiplier = s ? 0 : r_shadow_bouncegrid_dynamic_dlightparticlemultiplier.value;
2526 settings->hitmodels = s ? false : r_shadow_bouncegrid_dynamic_hitmodels.integer != 0;
2527 settings->includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
2528 settings->lightradiusscale = (s ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_dynamic_lightradiusscale.value);
2529 settings->maxbounce = (s ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_dynamic_maxbounce.integer);
2530 settings->particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
2531 settings->particleintensity = r_shadow_bouncegrid_particleintensity.value * (settings->directionalshading ? 4.0f : 1.0f) * 16384 / (spacing * spacing) / 262144.0f;
2532 settings->maxphotons = s ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_dynamic_maxphotons.integer;
2533 settings->energyperphoton = spacing * spacing / quality;
2534 settings->spacing[0] = spacing;
2535 settings->spacing[1] = spacing;
2536 settings->spacing[2] = spacing;
2537 settings->rng_type = r_shadow_bouncegrid_rng_type.integer;
2538 settings->rng_seed = r_shadow_bouncegrid_rng_seed.integer;
2539 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
2540 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
2541 settings->normalizevectors = r_shadow_bouncegrid_normalizevectors.integer != 0;
2543 // bound the values for sanity
2544 settings->maxphotons = bound(1, settings->maxphotons, 25000000);
2545 settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
2546 settings->maxbounce = bound(0, settings->maxbounce, 16);
2547 settings->spacing[0] = bound(1, settings->spacing[0], 512);
2548 settings->spacing[1] = bound(1, settings->spacing[1], 512);
2549 settings->spacing[2] = bound(1, settings->spacing[2], 512);
2552 static void R_Shadow_BounceGrid_UpdateSpacing(void)
2563 r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
2565 // get the spacing values
2566 spacing[0] = settings->spacing[0];
2567 spacing[1] = settings->spacing[1];
2568 spacing[2] = settings->spacing[2];
2569 ispacing[0] = 1.0f / spacing[0];
2570 ispacing[1] = 1.0f / spacing[1];
2571 ispacing[2] = 1.0f / spacing[2];
2573 // calculate texture size enclosing entire world bounds at the spacing
2574 if (r_refdef.scene.worldmodel)
2578 qboolean bounds_set = false;
2582 // calculate bounds enclosing world lights as they should be noticably tighter
2583 // than the world bounds on maps with unlit monster containers (see e1m7 etc)
2584 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2585 for (lightindex = 0;lightindex < range;lightindex++)
2587 const vec_t *rtlmins, *rtlmaxs;
2589 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2593 rtlight = &light->rtlight;
2594 rtlmins = rtlight->cullmins;
2595 rtlmaxs = rtlight->cullmaxs;
2599 VectorCopy(rtlmins, mins);
2600 VectorCopy(rtlmaxs, maxs);
2605 mins[0] = min(mins[0], rtlmins[0]);
2606 mins[1] = min(mins[1], rtlmins[1]);
2607 mins[2] = min(mins[2], rtlmins[2]);
2608 maxs[0] = max(maxs[0], rtlmaxs[0]);
2609 maxs[1] = max(maxs[1], rtlmaxs[1]);
2610 maxs[2] = max(maxs[2], rtlmaxs[2]);
2614 // limit to no larger than the world bounds
2615 mins[0] = max(mins[0], r_refdef.scene.worldmodel->normalmins[0]);
2616 mins[1] = max(mins[1], r_refdef.scene.worldmodel->normalmins[1]);
2617 mins[2] = max(mins[2], r_refdef.scene.worldmodel->normalmins[2]);
2618 maxs[0] = min(maxs[0], r_refdef.scene.worldmodel->normalmaxs[0]);
2619 maxs[1] = min(maxs[1], r_refdef.scene.worldmodel->normalmaxs[1]);
2620 maxs[2] = min(maxs[2], r_refdef.scene.worldmodel->normalmaxs[2]);
2622 VectorMA(mins, -2.0f, spacing, mins);
2623 VectorMA(maxs, 2.0f, spacing, maxs);
2627 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
2628 VectorSet(maxs, 1048576.0f, 1048576.0f, 1048576.0f);
2630 VectorSubtract(maxs, mins, size);
2631 // now we can calculate the resolution we want
2632 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2633 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2634 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2635 // figure out the exact texture size (honoring power of 2 if required)
2636 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2637 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2638 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2639 if (vid.support.arb_texture_non_power_of_two)
2641 resolution[0] = c[0];
2642 resolution[1] = c[1];
2643 resolution[2] = c[2];
2647 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2648 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2649 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2651 size[0] = spacing[0] * resolution[0];
2652 size[1] = spacing[1] * resolution[1];
2653 size[2] = spacing[2] * resolution[2];
2655 // if dynamic we may or may not want to use the world bounds
2656 // if the dynamic size is smaller than the world bounds, use it instead
2657 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]))
2659 // we know the resolution we want
2660 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
2661 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
2662 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
2663 // now we can calculate the texture size (power of 2 if required)
2664 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2665 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2666 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2667 if (vid.support.arb_texture_non_power_of_two)
2669 resolution[0] = c[0];
2670 resolution[1] = c[1];
2671 resolution[2] = c[2];
2675 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2676 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2677 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2679 size[0] = spacing[0] * resolution[0];
2680 size[1] = spacing[1] * resolution[1];
2681 size[2] = spacing[2] * resolution[2];
2682 // center the rendering on the view
2683 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2684 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2685 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2688 // recalculate the maxs in case the resolution was not satisfactory
2689 VectorAdd(mins, size, maxs);
2691 // check if this changed the texture size
2692 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);
2693 r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
2694 VectorCopy(mins, r_shadow_bouncegrid_state.mins);
2695 VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
2696 VectorCopy(size, r_shadow_bouncegrid_state.size);
2697 VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
2698 VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
2699 VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
2701 // reallocate pixels for this update if needed...
2702 r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
2703 r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
2704 r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
2705 numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
2706 if (r_shadow_bouncegrid_state.numpixels != numpixels)
2708 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
2709 r_shadow_bouncegrid_state.highpixels = NULL;
2710 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2711 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2712 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2713 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2714 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2715 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2716 r_shadow_bouncegrid_state.numpixels = numpixels;
2719 // update the bouncegrid matrix to put it in the world properly
2720 memset(m, 0, sizeof(m));
2721 m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
2722 m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
2723 m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
2724 m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
2725 m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
2726 m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
2728 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
2731 // enumerate world rtlights and sum the overall amount of light in the world,
2732 // from that we can calculate a scaling factor to fairly distribute photons
2733 // to all the lights
2735 // this modifies rtlight->photoncolor and rtlight->photons
2736 static void R_Shadow_BounceGrid_AssignPhotons(r_shadow_bouncegrid_settings_t *settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
2738 float normalphotonscaling;
2739 float photonscaling;
2740 float photonintensity;
2741 float photoncount = 0.0f;
2742 float lightintensity;
2748 unsigned int lightindex;
2751 normalphotonscaling = 1.0f / max(0.0001f, settings->energyperphoton);
2752 for (lightindex = 0;lightindex < range2;lightindex++)
2754 if (lightindex < range)
2756 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2759 rtlight = &light->rtlight;
2760 VectorClear(rtlight->bouncegrid_photoncolor);
2761 rtlight->bouncegrid_photons = 0;
2762 rtlight->bouncegrid_hits = 0;
2763 rtlight->bouncegrid_traces = 0;
2764 rtlight->bouncegrid_effectiveradius = 0;
2765 if (!(light->flags & flag))
2767 if (settings->staticmode)
2769 // when static, we skip styled lights because they tend to change...
2770 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2773 else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
2778 rtlight = r_refdef.scene.lights[lightindex - range];
2779 VectorClear(rtlight->bouncegrid_photoncolor);
2780 rtlight->bouncegrid_photons = 0;
2781 rtlight->bouncegrid_hits = 0;
2782 rtlight->bouncegrid_traces = 0;
2783 rtlight->bouncegrid_effectiveradius = 0;
2785 // draw only visible lights (major speedup)
2786 radius = rtlight->radius * settings->lightradiusscale;
2787 cullmins[0] = rtlight->shadoworigin[0] - radius;
2788 cullmins[1] = rtlight->shadoworigin[1] - radius;
2789 cullmins[2] = rtlight->shadoworigin[2] - radius;
2790 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2791 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2792 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2793 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2794 if (!settings->staticmode)
2796 // skip if the expanded light box does not touch any visible leafs
2797 if (r_refdef.scene.worldmodel
2798 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2799 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2801 // skip if the expanded light box is not visible to traceline
2802 // note that PrepareLight already did this check but for a smaller box, so we
2803 // end up casting more traces per frame per light when using bouncegrid, which
2804 // is probably fine (and they use the same timer)
2805 if (r_shadow_culllights_trace.integer)
2807 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_shadow_culllights_trace_expand.value, r_shadow_culllights_trace_pad.value, r_refdef.view.origin, rtlight->cullmins, rtlight->cullmaxs))
2808 rtlight->trace_timer = realtime;
2809 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
2812 // skip if expanded light box is offscreen
2813 if (R_CullBox(cullmins, cullmaxs))
2815 // skip if overall light intensity is zero
2816 if (w * VectorLength2(rtlight->color) == 0.0f)
2819 // a light that does not emit any light before style is applied, can be
2820 // skipped entirely (it may just be a corona)
2821 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2823 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2824 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2825 // skip lights that will emit no photons
2826 if (!VectorLength2(rtlight->bouncegrid_photoncolor))
2828 // shoot particles from this light
2829 // use a calculation for the number of particles that will not
2830 // vary with lightstyle, otherwise we get randomized particle
2831 // distribution, the seeded random is only consistent for a
2832 // consistent number of particles on this light...
2833 s = rtlight->radius;
2834 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2835 if (lightindex >= range)
2836 lightintensity *= settings->dlightparticlemultiplier;
2837 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2838 photoncount += rtlight->bouncegrid_photons;
2839 VectorScale(rtlight->bouncegrid_photoncolor, settings->particleintensity * settings->energyperphoton, rtlight->bouncegrid_photoncolor);
2840 // if the lightstyle happens to be off right now, we can skip actually
2841 // firing the photons, but we did have to count them in the total.
2842 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2843 // rtlight->bouncegrid_photons = 0;
2845 // the user provided an energyperphoton value which we try to use
2846 // if that results in too many photons to shoot this frame, then we cap it
2847 // which causes photons to appear/disappear from frame to frame, so we don't
2848 // like doing that in the typical case
2849 photonscaling = 1.0f;
2850 photonintensity = 1.0f;
2851 if (photoncount > settings->maxphotons)
2853 photonscaling = settings->maxphotons / photoncount;
2854 photonintensity = 1.0f / photonscaling;
2857 // modify the lights to reflect our computed scaling
2858 for (lightindex = 0; lightindex < range2; lightindex++)
2860 if (lightindex < range)
2862 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2865 rtlight = &light->rtlight;
2868 rtlight = r_refdef.scene.lights[lightindex - range];
2869 rtlight->bouncegrid_photons *= photonscaling;
2870 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2874 static int R_Shadow_BounceGrid_SplatPathCompare(const void *pa, const void *pb)
2876 r_shadow_bouncegrid_splatpath_t *a = (r_shadow_bouncegrid_splatpath_t *)pa;
2877 r_shadow_bouncegrid_splatpath_t *b = (r_shadow_bouncegrid_splatpath_t *)pb;
2878 // we only really care about sorting by Z
2879 if (a->point[2] < b->point[2])
2881 if (a->point[2] > b->point[2])
2886 static void R_Shadow_BounceGrid_ClearPixels(void)
2888 // clear the highpixels array we'll be accumulating into
2889 if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2890 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2891 if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2892 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2893 r_shadow_bouncegrid_state.highpixels_index = 0;
2894 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2895 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2898 static void R_Shadow_BounceGrid_PerformSplats(void)
2900 r_shadow_bouncegrid_splatpath_t *splatpaths = r_shadow_bouncegrid_state.splatpaths;
2901 r_shadow_bouncegrid_splatpath_t *splatpath;
2902 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2903 int numsplatpaths = r_shadow_bouncegrid_state.numsplatpaths;
2908 vec_t lightpathsize_current;
2909 vec_t lightpathsize_perstep;
2910 float splatcolor[32];
2912 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2913 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2917 // hush warnings about uninitialized data - pixelbands doesn't change but...
2918 memset(splatcolor, 0, sizeof(splatcolor));
2920 // we use this a lot, so get a local copy
2921 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2923 // sort the splats before we execute them, to reduce cache misses
2924 if (r_shadow_bouncegrid_sortlightpaths.integer)
2925 qsort(splatpaths, numsplatpaths, sizeof(*splatpaths), R_Shadow_BounceGrid_SplatPathCompare);
2927 splatpath = splatpaths;
2928 for (splatindex = 0;splatindex < numsplatpaths;splatindex++, splatpath++)
2930 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2931 // accumulate average shotcolor
2932 VectorCopy(splatpath->splatdir, dir);
2933 splatcolor[ 0] = splatpath->splatcolor[0];
2934 splatcolor[ 1] = splatpath->splatcolor[1];
2935 splatcolor[ 2] = splatpath->splatcolor[2];
2936 splatcolor[ 3] = 0.0f;
2939 // store bentnormal in case the shader has a use for it,
2940 // bentnormal is an intensity-weighted average of the directions,
2941 // and will be normalized on conversion to texture pixels.
2942 splatcolor[ 4] = dir[0] * splatpath->splatintensity;
2943 splatcolor[ 5] = dir[1] * splatpath->splatintensity;
2944 splatcolor[ 6] = dir[2] * splatpath->splatintensity;
2945 splatcolor[ 7] = splatpath->splatintensity;
2946 // for each color component (R, G, B) calculate the amount that a
2947 // direction contributes
2948 splatcolor[ 8] = splatcolor[0] * max(0.0f, dir[0]);
2949 splatcolor[ 9] = splatcolor[0] * max(0.0f, dir[1]);
2950 splatcolor[10] = splatcolor[0] * max(0.0f, dir[2]);
2951 splatcolor[11] = 0.0f;
2952 splatcolor[12] = splatcolor[1] * max(0.0f, dir[0]);
2953 splatcolor[13] = splatcolor[1] * max(0.0f, dir[1]);
2954 splatcolor[14] = splatcolor[1] * max(0.0f, dir[2]);
2955 splatcolor[15] = 0.0f;
2956 splatcolor[16] = splatcolor[2] * max(0.0f, dir[0]);
2957 splatcolor[17] = splatcolor[2] * max(0.0f, dir[1]);
2958 splatcolor[18] = splatcolor[2] * max(0.0f, dir[2]);
2959 splatcolor[19] = 0.0f;
2960 // and do the same for negative directions
2961 splatcolor[20] = splatcolor[0] * max(0.0f, -dir[0]);
2962 splatcolor[21] = splatcolor[0] * max(0.0f, -dir[1]);
2963 splatcolor[22] = splatcolor[0] * max(0.0f, -dir[2]);
2964 splatcolor[23] = 0.0f;
2965 splatcolor[24] = splatcolor[1] * max(0.0f, -dir[0]);
2966 splatcolor[25] = splatcolor[1] * max(0.0f, -dir[1]);
2967 splatcolor[26] = splatcolor[1] * max(0.0f, -dir[2]);
2968 splatcolor[27] = 0.0f;
2969 splatcolor[28] = splatcolor[2] * max(0.0f, -dir[0]);
2970 splatcolor[29] = splatcolor[2] * max(0.0f, -dir[1]);
2971 splatcolor[30] = splatcolor[2] * max(0.0f, -dir[2]);
2972 splatcolor[31] = 0.0f;
2974 // calculate the number of steps we need to traverse this distance
2975 VectorCopy(splatpath->point, steppos);
2976 VectorCopy(splatpath->step, stepdelta);
2977 numsteps = splatpath->remainingsplats;
2978 lightpathsize_current = splatpath->splatsize_current + 1.0f; // add 1.0 for the gradient fade around the sphere
2979 lightpathsize_perstep = splatpath->splatsize_perstep;
2980 for (step = 0;step < numsteps;step++)
2982 // the middle row/column/layer of each splat are full intensity
2985 if (lightpathsize_current > MAXBOUNCEGRIDSPLATSIZE)
2986 lightpathsize_current = MAXBOUNCEGRIDSPLATSIZE;
2987 splatmins[0] = max(1.0f, steppos[0] - lightpathsize_current * 0.5f);
2988 splatmins[1] = max(1.0f, steppos[1] - lightpathsize_current * 0.5f);
2989 splatmins[2] = max(1.0f, steppos[2] - lightpathsize_current * 0.5f);
2990 splatmaxs[0] = min(steppos[0] + lightpathsize_current * 0.5f, resolution[0] - 1.0f);
2991 splatmaxs[1] = min(steppos[1] + lightpathsize_current * 0.5f, resolution[1] - 1.0f);
2992 splatmaxs[2] = min(steppos[2] + lightpathsize_current * 0.5f, resolution[2] - 1.0f);
2993 if (splatmaxs[0] > splatmins[0] && splatmaxs[1] > splatmins[1] && splatmaxs[2] > splatmins[2])
2995 // it is within bounds... do the real work now
2996 int xi, yi, zi, band, row;
3000 float colorscale = 1.0f / lightpathsize_current;
3001 r_refdef.stats[r_stat_bouncegrid_splats]++;
3002 // accumulate light onto the pixels
3003 for (zi = (int)floor(splatmins[2]);zi < splatmaxs[2];zi++)
3005 pixelpos[2] = zi + 0.5f;
3006 for (yi = (int)floor(splatmins[1]); yi < splatmaxs[1]; yi++)
3008 pixelpos[1] = yi + 0.5f;
3009 row = (zi*resolution[1] + yi)*resolution[0];
3010 for (xi = (int)floor(splatmins[0]); xi < splatmaxs[0]; xi++)
3012 pixelpos[0] = xi + 0.5f;
3013 // simple radial antialiased sphere - linear gradient fade over 1 pixel from the edge
3014 w = lightpathsize_current - VectorDistance(pixelpos, steppos);
3020 p = highpixels + 4 * (row + xi);
3021 for (band = 0; band < pixelbands; band++, p += pixelsperband * 4)
3023 // add to the pixel color
3024 p[0] += splatcolor[band * 4 + 0] * w;
3025 p[1] += splatcolor[band * 4 + 1] * w;
3026 p[2] += splatcolor[band * 4 + 2] * w;
3027 p[3] += splatcolor[band * 4 + 3] * w;
3034 VectorAdd(steppos, stepdelta, steppos);
3035 lightpathsize_current += lightpathsize_perstep;
3040 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
3042 const float *inpixel;
3044 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
3047 unsigned int x, y, z;
3048 unsigned int resolution[3];
3049 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3050 for (pixelband = 0;pixelband < pixelbands;pixelband++)
3052 for (z = 1;z < resolution[2]-1;z++)
3054 for (y = 1;y < resolution[1]-1;y++)
3057 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3058 inpixel = inpixels + 4*index;
3059 outpixel = outpixels + 4*index;
3060 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
3062 outpixel[0] = (inpixel[0] + inpixel[ off] + inpixel[0-off]) * (1.0f / 3.0);
3063 outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
3064 outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
3065 outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
3072 static void R_Shadow_BounceGrid_BlurPixels(void)
3075 unsigned int resolution[3];
3077 if (!r_shadow_bouncegrid_state.settings.blur)
3080 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3082 pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3083 pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
3084 pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3085 pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
3088 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
3090 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
3092 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
3094 // toggle the state, highpixels now points to pixels[3] result
3095 r_shadow_bouncegrid_state.highpixels_index ^= 1;
3096 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3099 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
3101 int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
3102 unsigned char *pixelsbgra8 = NULL;
3103 unsigned char *pixelbgra8;
3104 unsigned short *pixelsrgba16f = NULL;
3105 unsigned short *pixelrgba16f;
3106 float *pixelsrgba32f = NULL;
3107 float *highpixels = r_shadow_bouncegrid_state.highpixels;
3110 unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
3111 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
3112 unsigned int pixelband;
3113 unsigned int x, y, z;
3114 unsigned int index, bandindex;
3115 unsigned int resolution[3];
3117 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3119 if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
3121 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3122 r_shadow_bouncegrid_state.texture = NULL;
3125 // if bentnormals exist, we need to normalize and bias them for the shader
3129 for (z = 0;z < resolution[2]-1;z++)
3131 for (y = 0;y < resolution[1]-1;y++)
3134 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3135 highpixel = highpixels + 4*index;
3136 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3138 // only convert pixels that were hit by photons
3139 if (highpixel[3] != 0.0f)
3140 VectorNormalize(highpixel);
3141 VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
3142 highpixel[pixelsperband * 4 + 3] = 1.0f;
3148 // start by clearing the pixels array - we won't be writing to all of it
3150 // then process only the pixels that have at least some color, skipping
3151 // the higher bands for speed on pixels that are black
3152 switch (floatcolors)
3155 if (r_shadow_bouncegrid_state.u8pixels == NULL)
3156 r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
3157 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
3158 for (pixelband = 0;pixelband < pixelbands;pixelband++)
3161 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
3163 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
3165 for (z = 1;z < resolution[2]-1;z++)
3167 for (y = 1;y < resolution[1]-1;y++)
3171 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3172 highpixel = highpixels + 4*index;
3173 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3175 // only convert pixels that were hit by photons
3176 if (VectorLength2(highpixel))
3178 // normalize the bentnormal now
3181 VectorNormalize(highpixel + pixelsperband * 4);
3182 highpixel[pixelsperband * 4 + 3] = 1.0f;
3184 // process all of the pixelbands for this pixel
3185 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3187 pixelbgra8 = pixelsbgra8 + 4*bandindex;
3188 bandpixel = highpixels + 4*bandindex;
3189 c[0] = (int)(bandpixel[0]*256.0f);
3190 c[1] = (int)(bandpixel[1]*256.0f);
3191 c[2] = (int)(bandpixel[2]*256.0f);
3192 c[3] = (int)(bandpixel[3]*256.0f);
3193 pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
3194 pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
3195 pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
3196 pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
3203 if (!r_shadow_bouncegrid_state.createtexture)
3204 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3206 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);
3209 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
3210 r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3211 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
3212 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3213 for (z = 1;z < resolution[2]-1;z++)
3215 for (y = 1;y < resolution[1]-1;y++)
3219 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3220 highpixel = highpixels + 4*index;
3221 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3223 // only convert pixels that were hit by photons
3224 if (VectorLength2(highpixel))
3226 // process all of the pixelbands for this pixel
3227 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3229 // time to have fun with IEEE 754 bit hacking...
3232 unsigned int raw[4];
3234 pixelrgba16f = pixelsrgba16f + 4*bandindex;
3235 bandpixel = highpixels + 4*bandindex;
3236 VectorCopy4(bandpixel, u.f);
3237 VectorCopy4(u.raw, c);
3238 // this math supports negative numbers, snaps denormals to zero
3239 //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
3240 //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
3241 //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
3242 //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
3243 // this math does not support negative
3244 pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
3245 pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
3246 pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
3247 pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
3254 if (!r_shadow_bouncegrid_state.createtexture)
3255 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3257 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);
3260 // our native format happens to match, so this is easy.
3261 pixelsrgba32f = highpixels;
3263 if (!r_shadow_bouncegrid_state.createtexture)
3264 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3266 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);
3270 r_shadow_bouncegrid_state.lastupdatetime = realtime;
3273 static void R_Shadow_BounceGrid_TracePhotons(r_shadow_bouncegrid_settings_t settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
3275 vec3_t bouncerandom[10];
3278 int hitsupercontentsmask;
3279 int skipsupercontentsmask;
3280 int skipmaterialflagsmask;
3284 float bounceminimumintensity2;
3286 //trace_t cliptrace2;
3287 //trace_t cliptrace3;
3288 unsigned int lightindex;
3290 randomseed_t randomseed;
3292 vec3_t baseshotcolor;
3298 vec_t distancetraveled;
3302 // compute a seed for the unstable random modes
3303 Math_RandomSeed_FromInts(&randomseed, 0, 0, 0, realtime * 1000.0);
3304 seed = realtime * 1000.0;
3306 r_shadow_bouncegrid_state.numsplatpaths = 0;
3308 // figure out what we want to interact with
3309 if (settings.hitmodels)
3310 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
3312 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
3313 skipsupercontentsmask = 0;
3314 skipmaterialflagsmask = MATERIALFLAGMASK_TRANSLUCENT;
3315 maxbounce = settings.maxbounce;
3317 for (lightindex = 0;lightindex < range2;lightindex++)
3319 if (lightindex < range)
3321 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3324 rtlight = &light->rtlight;
3327 rtlight = r_refdef.scene.lights[lightindex - range];
3328 // note that this code used to keep track of residual photons and
3329 // distribute them evenly to achieve exactly a desired photon count,
3330 // but that caused unwanted flickering in dynamic mode
3331 shootparticles = (int)floor(rtlight->bouncegrid_photons);
3332 // skip if we won't be shooting any photons
3333 if (!shootparticles)
3335 radius = rtlight->radius * settings.lightradiusscale;
3336 //s = settings.particleintensity / shootparticles;
3337 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
3338 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
3339 if (VectorLength2(baseshotcolor) <= 0.0f)
3341 r_refdef.stats[r_stat_bouncegrid_lights]++;
3342 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
3343 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
3344 bounceminimumintensity2 = VectorLength(baseshotcolor) * settings.bounceminimumintensity2;
3346 // for seeded random we start the RNG with the position of the light
3347 if (settings.rng_seed >= 0)
3355 u.f[0] = rtlight->shadoworigin[0];
3356 u.f[1] = rtlight->shadoworigin[1];
3357 u.f[2] = rtlight->shadoworigin[2];
3359 switch (settings.rng_type)
3363 // we have to shift the seed provided by the user because the result must be odd
3364 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3] ^ (settings.rng_seed << 1));
3367 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3] ^ settings.rng_seed;
3372 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
3374 VectorCopy(baseshotcolor, shotcolor);
3375 VectorCopy(rtlight->shadoworigin, clipstart);
3376 switch (settings.rng_type)
3380 VectorLehmerRandom(&randomseed, clipend);
3381 if (settings.bounceanglediffuse)
3383 // we want random to be stable, so we still have to do all the random we would have done
3384 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3385 VectorLehmerRandom(&randomseed, bouncerandom[bouncecount]);
3389 VectorCheeseRandom(seed, clipend);
3390 if (settings.bounceanglediffuse)
3392 // we want random to be stable, so we still have to do all the random we would have done
3393 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3394 VectorCheeseRandom(seed, bouncerandom[bouncecount]);
3399 // we want a uniform distribution spherically, not merely within the sphere
3400 if (settings.normalizevectors)
3401 VectorNormalize(clipend);
3403 VectorMA(clipstart, radius, clipend, clipend);
3404 distancetraveled = 0.0f;
3405 for (bouncecount = 0;;bouncecount++)
3407 r_refdef.stats[r_stat_bouncegrid_traces]++;
3408 rtlight->bouncegrid_traces++;
3409 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
3410 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
3411 if (settings.staticmode || settings.rng_seed < 0)
3413 // static mode fires a LOT of rays but none of them are identical, so they are not cached
3414 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
3415 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);
3419 // dynamic mode fires many rays and most will match the cache from the previous frame
3420 cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
3422 if (bouncecount > 0 || settings.includedirectlighting)
3425 VectorCopy(cliptrace.endpos, hitpos);
3426 R_Shadow_BounceGrid_AddSplatPath(clipstart, hitpos, shotcolor, distancetraveled);
3428 distancetraveled += VectorDistance(clipstart, cliptrace.endpos);
3429 s = VectorDistance(rtlight->shadoworigin, cliptrace.endpos);
3430 if (rtlight->bouncegrid_effectiveradius < s)
3431 rtlight->bouncegrid_effectiveradius = s;
3432 if (cliptrace.fraction >= 1.0f)
3434 r_refdef.stats[r_stat_bouncegrid_hits]++;
3435 rtlight->bouncegrid_hits++;
3436 if (bouncecount >= maxbounce)
3438 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
3439 // also clamp the resulting color to never add energy, even if the user requests extreme values
3440 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
3441 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
3443 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
3444 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
3445 surfcolor[0] = min(surfcolor[0], 1.0f);
3446 surfcolor[1] = min(surfcolor[1], 1.0f);
3447 surfcolor[2] = min(surfcolor[2], 1.0f);
3448 VectorMultiply(shotcolor, surfcolor, shotcolor);
3449 if (VectorLength2(shotcolor) <= bounceminimumintensity2)
3451 r_refdef.stats[r_stat_bouncegrid_bounces]++;
3452 if (settings.bounceanglediffuse)
3454 // random direction, primarily along plane normal
3455 s = VectorDistance(cliptrace.endpos, clipend);
3456 VectorMA(cliptrace.plane.normal, 0.95f, bouncerandom[bouncecount], clipend);
3457 VectorNormalize(clipend);
3458 VectorScale(clipend, s, clipend);
3462 // reflect the remaining portion of the line across plane normal
3463 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
3464 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
3466 // calculate the new line start and end
3467 VectorCopy(cliptrace.endpos, clipstart);
3468 VectorAdd(clipstart, clipend, clipend);
3474 void R_Shadow_UpdateBounceGridTexture(void)
3476 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3477 r_shadow_bouncegrid_settings_t settings;
3478 qboolean enable = false;
3479 qboolean settingschanged;
3480 unsigned int range; // number of world lights
3481 unsigned int range1; // number of dynamic lights (or zero if disabled)
3482 unsigned int range2; // range+range1
3484 enable = R_Shadow_BounceGrid_CheckEnable(flag);
3486 R_Shadow_BounceGrid_GenerateSettings(&settings);
3488 // changing intensity does not require an update
3489 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
3491 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
3493 // when settings change, we free everything as it is just simpler that way.
3494 if (settingschanged || !enable)
3496 // not enabled, make sure we free anything we don't need anymore.
3497 if (r_shadow_bouncegrid_state.texture)
3499 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3500 r_shadow_bouncegrid_state.texture = NULL;
3502 r_shadow_bouncegrid_state.highpixels = NULL;
3503 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
3504 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
3505 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
3506 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
3507 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
3508 r_shadow_bouncegrid_state.maxsplatpaths = 0;
3509 r_shadow_bouncegrid_state.numpixels = 0;
3510 r_shadow_bouncegrid_state.directional = false;
3516 // if all the settings seem identical to the previous update, return
3517 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
3520 // store the new settings
3521 r_shadow_bouncegrid_state.settings = settings;
3523 R_Shadow_BounceGrid_UpdateSpacing();
3525 // get the range of light numbers we'll be looping over:
3526 // range = static lights
3527 // range1 = dynamic lights (optional)
3528 // range2 = range + range1
3529 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3530 range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
3531 range2 = range + range1;
3533 // calculate weighting factors for distributing photons among the lights
3534 R_Shadow_BounceGrid_AssignPhotons(&settings, range, range1, range2, flag);
3536 // trace the photons from lights and accumulate illumination
3537 R_Shadow_BounceGrid_TracePhotons(settings, range, range1, range2, flag);
3539 // clear the texture
3540 R_Shadow_BounceGrid_ClearPixels();
3542 // accumulate the light splatting into texture
3543 R_Shadow_BounceGrid_PerformSplats();
3545 // apply a mild blur filter to the texture
3546 R_Shadow_BounceGrid_BlurPixels();
3548 // convert the pixels to lower precision and upload the texture
3549 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
3551 // after we compute the static lighting we don't need to keep the highpixels array around
3552 if (settings.staticmode)
3554 r_shadow_bouncegrid_state.highpixels = NULL;
3555 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
3556 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
3557 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
3558 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
3559 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
3560 r_shadow_bouncegrid_state.maxsplatpaths = 0;
3564 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
3566 R_Shadow_RenderMode_Reset();
3567 GL_BlendFunc(GL_ONE, GL_ONE);
3568 GL_DepthRange(0, 1);
3569 GL_DepthTest(r_showshadowvolumes.integer < 2);
3570 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
3571 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
3572 GL_CullFace(GL_NONE);
3573 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
3576 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
3578 R_Shadow_RenderMode_Reset();
3579 GL_BlendFunc(GL_ONE, GL_ONE);
3580 GL_DepthRange(0, 1);
3581 GL_DepthTest(r_showlighting.integer < 2);
3582 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
3584 GL_DepthFunc(GL_EQUAL);
3585 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
3586 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
3589 void R_Shadow_RenderMode_End(void)
3591 R_Shadow_RenderMode_Reset();
3592 R_Shadow_RenderMode_ActiveLight(NULL);
3594 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3595 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3598 int bboxedges[12][2] =
3617 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
3619 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
3621 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
3622 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
3623 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
3624 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
3627 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
3628 return true; // invisible
3629 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
3630 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
3631 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
3632 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
3633 r_refdef.stats[r_stat_lights_scissored]++;
3637 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3639 // used to display how many times a surface is lit for level design purposes
3640 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3641 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3645 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])
3647 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3648 R_SetupShader_Surface(ambientcolor, diffusecolor, specularcolor, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
3652 extern cvar_t gl_lightmaps;
3653 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3656 float ambientcolor[3], diffusecolor[3], specularcolor[3];
3657 VectorM(rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient, rsurface.texture->render_rtlight_diffuse, ambientcolor);
3658 VectorM(rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient), rsurface.texture->render_rtlight_diffuse, diffusecolor);
3659 VectorM(rsurface.rtlight->specularscale, rsurface.texture->render_rtlight_specular, specularcolor);
3660 if (!r_shadow_usenormalmap.integer)
3662 VectorMAM(1.0f, ambientcolor, 1.0f, diffusecolor, ambientcolor);
3663 VectorClear(diffusecolor);
3664 VectorClear(specularcolor);
3666 VectorMultiply(ambientcolor, rsurface.rtlight->currentcolor, ambientcolor);
3667 VectorMultiply(diffusecolor, rsurface.rtlight->currentcolor, diffusecolor);
3668 VectorMultiply(specularcolor, rsurface.rtlight->currentcolor, specularcolor);
3669 if (VectorLength2(ambientcolor) + VectorLength2(diffusecolor) + VectorLength2(specularcolor) < (1.0f / 1048576.0f))
3671 negated = (rsurface.rtlight->currentcolor[0] + rsurface.rtlight->currentcolor[1] + rsurface.rtlight->currentcolor[2] < 0) && vid.support.ext_blend_subtract;
3674 VectorNegate(ambientcolor, ambientcolor);
3675 VectorNegate(diffusecolor, diffusecolor);
3676 VectorNegate(specularcolor, specularcolor);
3677 GL_BlendEquationSubtract(true);
3679 RSurf_SetupDepthAndCulling();
3680 switch (r_shadow_rendermode)
3682 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3683 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3684 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
3686 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3687 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, ambientcolor, diffusecolor, specularcolor);
3690 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3694 GL_BlendEquationSubtract(false);
3697 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)
3699 matrix4x4_t tempmatrix = *matrix;
3700 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3702 // if this light has been compiled before, free the associated data
3703 R_RTLight_Uncompile(rtlight);
3705 // clear it completely to avoid any lingering data
3706 memset(rtlight, 0, sizeof(*rtlight));
3708 // copy the properties
3709 rtlight->matrix_lighttoworld = tempmatrix;
3710 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3711 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3712 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3713 VectorCopy(color, rtlight->color);
3714 rtlight->cubemapname[0] = 0;
3715 if (cubemapname && cubemapname[0])
3716 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3717 rtlight->shadow = shadow;
3718 rtlight->corona = corona;
3719 rtlight->style = style;
3720 rtlight->isstatic = isstatic;
3721 rtlight->coronasizescale = coronasizescale;
3722 rtlight->ambientscale = ambientscale;
3723 rtlight->diffusescale = diffusescale;
3724 rtlight->specularscale = specularscale;
3725 rtlight->flags = flags;
3727 // compute derived data
3728 //rtlight->cullradius = rtlight->radius;
3729 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3730 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3731 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3732 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3733 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3734 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3735 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3738 // compiles rtlight geometry
3739 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3740 void R_RTLight_Compile(rtlight_t *rtlight)
3743 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3744 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3745 entity_render_t *ent = r_refdef.scene.worldentity;
3746 dp_model_t *model = r_refdef.scene.worldmodel;
3747 unsigned char *data;
3750 // compile the light
3751 rtlight->compiled = true;
3752 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3753 rtlight->static_numleafs = 0;
3754 rtlight->static_numleafpvsbytes = 0;
3755 rtlight->static_leaflist = NULL;
3756 rtlight->static_leafpvs = NULL;
3757 rtlight->static_numsurfaces = 0;
3758 rtlight->static_surfacelist = NULL;
3759 rtlight->static_shadowmap_receivers = 0x3F;
3760 rtlight->static_shadowmap_casters = 0x3F;
3761 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3762 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3763 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3764 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3765 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3766 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3768 if (model && model->GetLightInfo)
3770 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3771 r_shadow_compilingrtlight = rtlight;
3772 R_FrameData_SetMark();
3773 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);
3774 R_FrameData_ReturnToMark();
3775 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3776 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3777 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3778 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3779 rtlight->static_numsurfaces = numsurfaces;
3780 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3781 rtlight->static_numleafs = numleafs;
3782 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3783 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3784 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3785 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3786 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3787 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3788 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3789 if (rtlight->static_numsurfaces)
3790 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3791 if (rtlight->static_numleafs)
3792 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3793 if (rtlight->static_numleafpvsbytes)
3794 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3795 if (rtlight->static_numshadowtrispvsbytes)
3796 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3797 if (rtlight->static_numlighttrispvsbytes)
3798 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3799 R_FrameData_SetMark();
3800 switch (rtlight->shadowmode)
3802 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3803 if (model->CompileShadowMap && rtlight->shadow)
3804 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3807 if (model->CompileShadowVolume && rtlight->shadow)
3808 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3811 R_FrameData_ReturnToMark();
3812 // now we're done compiling the rtlight
3813 r_shadow_compilingrtlight = NULL;
3817 // use smallest available cullradius - box radius or light radius
3818 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3819 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3821 shadowzpasstris = 0;
3822 if (rtlight->static_meshchain_shadow_zpass)
3823 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3824 shadowzpasstris += mesh->numtriangles;
3826 shadowzfailtris = 0;
3827 if (rtlight->static_meshchain_shadow_zfail)
3828 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3829 shadowzfailtris += mesh->numtriangles;
3832 if (rtlight->static_numlighttrispvsbytes)
3833 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3834 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3838 if (rtlight->static_numshadowtrispvsbytes)
3839 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3840 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3843 if (developer_extra.integer)
3844 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);
3847 void R_RTLight_Uncompile(rtlight_t *rtlight)
3849 if (rtlight->compiled)
3851 if (rtlight->static_meshchain_shadow_zpass)
3852 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3853 rtlight->static_meshchain_shadow_zpass = NULL;
3854 if (rtlight->static_meshchain_shadow_zfail)
3855 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3856 rtlight->static_meshchain_shadow_zfail = NULL;
3857 if (rtlight->static_meshchain_shadow_shadowmap)
3858 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3859 rtlight->static_meshchain_shadow_shadowmap = NULL;
3860 // these allocations are grouped
3861 if (rtlight->static_surfacelist)
3862 Mem_Free(rtlight->static_surfacelist);
3863 rtlight->static_numleafs = 0;
3864 rtlight->static_numleafpvsbytes = 0;
3865 rtlight->static_leaflist = NULL;
3866 rtlight->static_leafpvs = NULL;
3867 rtlight->static_numsurfaces = 0;
3868 rtlight->static_surfacelist = NULL;
3869 rtlight->static_numshadowtrispvsbytes = 0;
3870 rtlight->static_shadowtrispvs = NULL;
3871 rtlight->static_numlighttrispvsbytes = 0;
3872 rtlight->static_lighttrispvs = NULL;
3873 rtlight->compiled = false;
3877 void R_Shadow_UncompileWorldLights(void)
3881 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3882 for (lightindex = 0;lightindex < range;lightindex++)
3884 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3887 R_RTLight_Uncompile(&light->rtlight);
3891 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3895 // reset the count of frustum planes
3896 // see rtlight->cached_frustumplanes definition for how much this array
3898 rtlight->cached_numfrustumplanes = 0;
3900 if (r_trippy.integer)
3903 // haven't implemented a culling path for ortho rendering
3904 if (!r_refdef.view.useperspective)
3906 // check if the light is on screen and copy the 4 planes if it is
3907 for (i = 0;i < 4;i++)
3908 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3911 for (i = 0;i < 4;i++)
3912 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3917 // generate a deformed frustum that includes the light origin, this is
3918 // used to cull shadow casting surfaces that can not possibly cast a
3919 // shadow onto the visible light-receiving surfaces, which can be a
3922 // if the light origin is onscreen the result will be 4 planes exactly
3923 // if the light origin is offscreen on only one axis the result will
3924 // be exactly 5 planes (split-side case)
3925 // if the light origin is offscreen on two axes the result will be
3926 // exactly 4 planes (stretched corner case)
3927 for (i = 0;i < 4;i++)
3929 // quickly reject standard frustum planes that put the light
3930 // origin outside the frustum
3931 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3934 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3936 // if all the standard frustum planes were accepted, the light is onscreen
3937 // otherwise we need to generate some more planes below...
3938 if (rtlight->cached_numfrustumplanes < 4)
3940 // at least one of the stock frustum planes failed, so we need to
3941 // create one or two custom planes to enclose the light origin
3942 for (i = 0;i < 4;i++)
3944 // create a plane using the view origin and light origin, and a
3945 // single point from the frustum corner set
3946 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3947 VectorNormalize(plane.normal);
3948 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3949 // see if this plane is backwards and flip it if so
3950 for (j = 0;j < 4;j++)
3951 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3955 VectorNegate(plane.normal, plane.normal);
3957 // flipped plane, test again to see if it is now valid
3958 for (j = 0;j < 4;j++)
3959 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3961 // if the plane is still not valid, then it is dividing the
3962 // frustum and has to be rejected
3966 // we have created a valid plane, compute extra info
3967 PlaneClassify(&plane);
3969 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3971 // if we've found 5 frustum planes then we have constructed a
3972 // proper split-side case and do not need to keep searching for
3973 // planes to enclose the light origin
3974 if (rtlight->cached_numfrustumplanes == 5)
3982 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3984 plane = rtlight->cached_frustumplanes[i];
3985 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));
3990 // now add the light-space box planes if the light box is rotated, as any
3991 // caster outside the oriented light box is irrelevant (even if it passed
3992 // the worldspace light box, which is axial)
3993 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3995 for (i = 0;i < 6;i++)
3999 v[i >> 1] = (i & 1) ? -1 : 1;
4000 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
4001 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
4002 plane.dist = VectorNormalizeLength(plane.normal);
4003 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
4004 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4010 // add the world-space reduced box planes
4011 for (i = 0;i < 6;i++)
4013 VectorClear(plane.normal);
4014 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
4015 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
4016 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4025 // reduce all plane distances to tightly fit the rtlight cull box, which
4027 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4028 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4029 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4030 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4031 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4032 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4033 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4034 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4035 oldnum = rtlight->cached_numfrustumplanes;
4036 rtlight->cached_numfrustumplanes = 0;
4037 for (j = 0;j < oldnum;j++)
4039 // find the nearest point on the box to this plane
4040 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
4041 for (i = 1;i < 8;i++)
4043 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
4044 if (bestdist > dist)
4047 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);
4048 // if the nearest point is near or behind the plane, we want this
4049 // plane, otherwise the plane is useless as it won't cull anything
4050 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
4052 PlaneClassify(&rtlight->cached_frustumplanes[j]);
4053 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
4060 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
4064 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4066 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4069 GL_CullFace(GL_NONE);
4070 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
4071 for (;mesh;mesh = mesh->next)
4073 if (!mesh->sidetotals[r_shadow_shadowmapside])
4075 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
4076 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4077 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);
4081 else if (r_refdef.scene.worldentity->model)
4082 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);
4084 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4087 static void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
4089 qboolean zpass = false;
4092 int surfacelistindex;
4093 msurface_t *surface;
4095 // if triangle neighbors are disabled, shadowvolumes are disabled
4096 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
4099 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4101 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4104 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
4106 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
4107 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
4109 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
4110 for (;mesh;mesh = mesh->next)
4112 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->numtriangles;
4113 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4114 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
4116 // increment stencil if frontface is infront of depthbuffer
4117 GL_CullFace(r_refdef.view.cullface_back);
4118 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
4119 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);
4120 // decrement stencil if backface is infront of depthbuffer
4121 GL_CullFace(r_refdef.view.cullface_front);
4122 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
4124 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
4126 // decrement stencil if backface is behind depthbuffer
4127 GL_CullFace(r_refdef.view.cullface_front);
4128 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
4129 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);
4130 // increment stencil if frontface is behind depthbuffer
4131 GL_CullFace(r_refdef.view.cullface_back);
4132 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
4134 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);
4138 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
4140 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
4141 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
4142 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
4144 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
4145 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
4146 if (CHECKPVSBIT(trispvs, t))
4147 shadowmarklist[numshadowmark++] = t;
4149 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);
4151 else if (numsurfaces)
4153 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);
4156 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4159 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
4161 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
4162 vec_t relativeshadowradius;
4163 RSurf_ActiveModelEntity(ent, false, false, false);
4164 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
4165 // we need to re-init the shader for each entity because the matrix changed
4166 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
4167 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
4168 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
4169 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
4170 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
4171 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
4172 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
4173 switch (r_shadow_rendermode)
4175 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
4176 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4179 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4182 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4185 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
4187 // set up properties for rendering light onto this entity
4188 RSurf_ActiveModelEntity(ent, true, true, false);
4189 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
4190 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4191 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4192 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4195 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
4197 if (!r_refdef.scene.worldmodel->DrawLight)
4200 // set up properties for rendering light onto this entity
4201 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4202 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
4203 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4204 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4205 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4207 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
4209 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4212 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
4214 dp_model_t *model = ent->model;
4215 if (!model->DrawLight)
4218 R_Shadow_SetupEntityLight(ent);
4220 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
4222 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4225 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
4229 int numleafs, numsurfaces;
4230 int *leaflist, *surfacelist;
4231 unsigned char *leafpvs;
4232 unsigned char *shadowtrispvs;
4233 unsigned char *lighttrispvs;
4234 //unsigned char *surfacesides;
4235 int numlightentities;
4236 int numlightentities_noselfshadow;
4237 int numshadowentities;
4238 int numshadowentities_noselfshadow;
4239 // FIXME: bounds check lightentities and shadowentities, etc.
4240 static entity_render_t *lightentities[MAX_EDICTS];
4241 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
4242 static entity_render_t *shadowentities[MAX_EDICTS];
4243 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
4245 qboolean castshadows;
4247 rtlight->draw = false;
4248 rtlight->cached_numlightentities = 0;
4249 rtlight->cached_numlightentities_noselfshadow = 0;
4250 rtlight->cached_numshadowentities = 0;
4251 rtlight->cached_numshadowentities_noselfshadow = 0;
4252 rtlight->cached_numsurfaces = 0;
4253 rtlight->cached_lightentities = NULL;
4254 rtlight->cached_lightentities_noselfshadow = NULL;
4255 rtlight->cached_shadowentities = NULL;
4256 rtlight->cached_shadowentities_noselfshadow = NULL;
4257 rtlight->cached_shadowtrispvs = NULL;
4258 rtlight->cached_lighttrispvs = NULL;
4259 rtlight->cached_surfacelist = NULL;
4260 rtlight->shadowmapsidesize = 0;
4262 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
4263 // skip lights that are basically invisible (color 0 0 0)
4264 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
4266 // loading is done before visibility checks because loading should happen
4267 // all at once at the start of a level, not when it stalls gameplay.
4268 // (especially important to benchmarks)
4270 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
4272 if (rtlight->compiled)
4273 R_RTLight_Uncompile(rtlight);
4274 R_RTLight_Compile(rtlight);
4278 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
4280 // look up the light style value at this time
4281 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4282 VectorScale(rtlight->color, f, rtlight->currentcolor);
4284 if (rtlight->selected)
4286 f = 2 + sin(realtime * M_PI * 4.0);
4287 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
4291 // skip if lightstyle is currently off
4292 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
4295 // skip processing on corona-only lights
4299 // skip if the light box is not touching any visible leafs
4300 if (r_shadow_culllights_pvs.integer
4301 && r_refdef.scene.worldmodel
4302 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
4303 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, rtlight->cullmins, rtlight->cullmaxs))
4306 // skip if the light box is not visible to traceline
4307 if (r_shadow_culllights_trace.integer)
4309 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_shadow_culllights_trace_expand.value, r_shadow_culllights_trace_pad.value, r_refdef.view.origin, rtlight->cullmins, rtlight->cullmaxs))
4310 rtlight->trace_timer = realtime;
4311 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
4315 // skip if the light box is off screen
4316 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
4319 // in the typical case this will be quickly replaced by GetLightInfo
4320 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
4321 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
4323 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4325 // 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
4326 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
4329 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
4331 // compiled light, world available and can receive realtime lighting
4332 // retrieve leaf information
4333 numleafs = rtlight->static_numleafs;
4334 leaflist = rtlight->static_leaflist;
4335 leafpvs = rtlight->static_leafpvs;
4336 numsurfaces = rtlight->static_numsurfaces;
4337 surfacelist = rtlight->static_surfacelist;
4338 //surfacesides = NULL;
4339 shadowtrispvs = rtlight->static_shadowtrispvs;
4340 lighttrispvs = rtlight->static_lighttrispvs;
4342 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4344 // dynamic light, world available and can receive realtime lighting
4345 // calculate lit surfaces and leafs
4346 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);
4347 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4348 leaflist = r_shadow_buffer_leaflist;
4349 leafpvs = r_shadow_buffer_leafpvs;
4350 surfacelist = r_shadow_buffer_surfacelist;
4351 //surfacesides = r_shadow_buffer_surfacesides;
4352 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4353 lighttrispvs = r_shadow_buffer_lighttrispvs;
4354 // if the reduced leaf bounds are offscreen, skip it
4355 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4366 //surfacesides = NULL;
4367 shadowtrispvs = NULL;
4368 lighttrispvs = NULL;
4370 // check if light is illuminating any visible leafs
4373 for (i = 0; i < numleafs; i++)
4374 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4380 // make a list of lit entities and shadow casting entities
4381 numlightentities = 0;
4382 numlightentities_noselfshadow = 0;
4383 numshadowentities = 0;
4384 numshadowentities_noselfshadow = 0;
4386 // add dynamic entities that are lit by the light
4387 for (i = 0; i < r_refdef.scene.numentities; i++)
4390 entity_render_t *ent = r_refdef.scene.entities[i];
4392 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4394 // skip the object entirely if it is not within the valid
4395 // shadow-casting region (which includes the lit region)
4396 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
4398 if (!(model = ent->model))
4400 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4402 // this entity wants to receive light, is visible, and is
4403 // inside the light box
4404 // TODO: check if the surfaces in the model can receive light
4405 // so now check if it's in a leaf seen by the light
4406 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))
4408 if (ent->flags & RENDER_NOSELFSHADOW)
4409 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
4411 lightentities[numlightentities++] = ent;
4412 // since it is lit, it probably also casts a shadow...
4413 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4414 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4415 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4417 // note: exterior models without the RENDER_NOSELFSHADOW
4418 // flag still create a RENDER_NOSELFSHADOW shadow but
4419 // are lit normally, this means that they are
4420 // self-shadowing but do not shadow other
4421 // RENDER_NOSELFSHADOW entities such as the gun
4422 // (very weird, but keeps the player shadow off the gun)
4423 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4424 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4426 shadowentities[numshadowentities++] = ent;
4429 else if (ent->flags & RENDER_SHADOW)
4431 // this entity is not receiving light, but may still need to
4433 // TODO: check if the surfaces in the model can cast shadow
4434 // now check if it is in a leaf seen by the light
4435 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))
4437 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4438 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4439 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4441 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4442 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4444 shadowentities[numshadowentities++] = ent;
4449 // return if there's nothing at all to light
4450 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4453 // count this light in the r_speeds
4454 r_refdef.stats[r_stat_lights]++;
4456 // flag it as worth drawing later
4457 rtlight->draw = true;
4459 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
4460 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4462 numshadowentities = numshadowentities_noselfshadow = 0;
4463 rtlight->castshadows = castshadows;
4465 // cache all the animated entities that cast a shadow but are not visible
4466 for (i = 0; i < numshadowentities; i++)
4467 R_AnimCache_GetEntity(shadowentities[i], false, false);
4468 for (i = 0; i < numshadowentities_noselfshadow; i++)
4469 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4471 // 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)
4472 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
4474 for (i = 0; i < numshadowentities_noselfshadow; i++)
4475 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
4476 numshadowentities_noselfshadow = 0;
4479 // we can convert noselfshadow to regular if there are no casters of that type
4480 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
4482 for (i = 0; i < numlightentities_noselfshadow; i++)
4483 lightentities[numlightentities++] = lightentities_noselfshadow[i];
4484 numlightentities_noselfshadow = 0;
4487 // allocate some temporary memory for rendering this light later in the frame
4488 // reusable buffers need to be copied, static data can be used as-is
4489 rtlight->cached_numlightentities = numlightentities;
4490 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
4491 rtlight->cached_numshadowentities = numshadowentities;
4492 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4493 rtlight->cached_numsurfaces = numsurfaces;
4494 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4495 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4496 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4497 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4498 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4500 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4501 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4502 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4503 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4504 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4508 // compiled light data
4509 rtlight->cached_shadowtrispvs = shadowtrispvs;
4510 rtlight->cached_lighttrispvs = lighttrispvs;
4511 rtlight->cached_surfacelist = surfacelist;
4514 if (R_Shadow_ShadowMappingEnabled())
4516 // figure out the shadowmapping parameters for this light
4517 vec3_t nearestpoint;
4520 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4521 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4522 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4523 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4524 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
4525 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4526 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4527 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4528 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
4532 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
4536 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4537 int numlightentities;
4538 int numlightentities_noselfshadow;
4539 int numshadowentities;
4540 int numshadowentities_noselfshadow;
4541 entity_render_t **lightentities;
4542 entity_render_t **lightentities_noselfshadow;
4543 entity_render_t **shadowentities;
4544 entity_render_t **shadowentities_noselfshadow;
4546 static unsigned char entitysides[MAX_EDICTS];
4547 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4553 matrix4x4_t radiustolight;
4555 // check if we cached this light this frame (meaning it is worth drawing)
4556 if (!rtlight->draw || !rtlight->castshadows)
4559 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
4560 if (rtlight->shadowmapatlassidesize == 0)
4562 rtlight->castshadows = false;
4566 // set up a scissor rectangle for this light
4567 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4570 // don't let sound skip if going slow
4571 if (r_refdef.scene.extraupdate)
4574 numlightentities = rtlight->cached_numlightentities;
4575 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4576 numshadowentities = rtlight->cached_numshadowentities;
4577 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4578 numsurfaces = rtlight->cached_numsurfaces;
4579 lightentities = rtlight->cached_lightentities;
4580 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4581 shadowentities = rtlight->cached_shadowentities;
4582 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4583 shadowtrispvs = rtlight->cached_shadowtrispvs;
4584 lighttrispvs = rtlight->cached_lighttrispvs;
4585 surfacelist = rtlight->cached_surfacelist;
4587 // make this the active rtlight for rendering purposes
4588 R_Shadow_RenderMode_ActiveLight(rtlight);
4590 radiustolight = rtlight->matrix_worldtolight;
4591 Matrix4x4_Abs(&radiustolight);
4593 size = rtlight->shadowmapatlassidesize;
4594 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4596 surfacesides = NULL;
4601 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4603 castermask = rtlight->static_shadowmap_casters;
4604 receivermask = rtlight->static_shadowmap_receivers;
4608 surfacesides = r_shadow_buffer_surfacesides;
4609 for (i = 0; i < numsurfaces; i++)
4611 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4612 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4613 castermask |= surfacesides[i];
4614 receivermask |= surfacesides[i];
4619 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
4620 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4621 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
4622 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4624 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4628 for (i = 0; i < numshadowentities; i++)
4629 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4630 for (i = 0; i < numshadowentities_noselfshadow; i++)
4631 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4634 // there is no need to render shadows for sides that have no receivers...
4635 castermask &= receivermask;
4637 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
4639 // render shadow casters into shadowmaps for this light
4640 for (side = 0; side < 6; side++)
4642 int bit = 1 << side;
4643 if (castermask & bit)
4645 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
4647 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4648 for (i = 0; i < numshadowentities; i++)
4649 if (entitysides[i] & bit)
4650 R_Shadow_DrawEntityShadow(shadowentities[i]);
4651 for (i = 0; i < numshadowentities_noselfshadow; i++)
4652 if (entitysides_noselfshadow[i] & bit)
4653 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4656 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
4657 if (numshadowentities_noselfshadow)
4659 for (side = 0; side < 6; side++)
4661 int bit = 1 << side;
4662 if (castermask & bit)
4664 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
4666 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4667 for (i = 0; i < numshadowentities; i++)
4668 if (entitysides[i] & bit)
4669 R_Shadow_DrawEntityShadow(shadowentities[i]);
4675 static void R_Shadow_DrawLight(rtlight_t *rtlight)
4679 unsigned char *shadowtrispvs, *lighttrispvs;
4680 int numlightentities;
4681 int numlightentities_noselfshadow;
4682 int numshadowentities;
4683 int numshadowentities_noselfshadow;
4684 entity_render_t **lightentities;
4685 entity_render_t **lightentities_noselfshadow;
4686 entity_render_t **shadowentities;
4687 entity_render_t **shadowentities_noselfshadow;
4689 qboolean castshadows;
4691 // check if we cached this light this frame (meaning it is worth drawing)
4695 // set up a scissor rectangle for this light
4696 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4699 // don't let sound skip if going slow
4700 if (r_refdef.scene.extraupdate)
4703 numlightentities = rtlight->cached_numlightentities;
4704 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4705 numshadowentities = rtlight->cached_numshadowentities;
4706 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4707 numsurfaces = rtlight->cached_numsurfaces;
4708 lightentities = rtlight->cached_lightentities;
4709 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4710 shadowentities = rtlight->cached_shadowentities;
4711 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4712 shadowtrispvs = rtlight->cached_shadowtrispvs;
4713 lighttrispvs = rtlight->cached_lighttrispvs;
4714 surfacelist = rtlight->cached_surfacelist;
4715 castshadows = rtlight->castshadows;
4717 // make this the active rtlight for rendering purposes
4718 R_Shadow_RenderMode_ActiveLight(rtlight);
4720 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4722 // optionally draw visible shape of the shadow volumes
4723 // for performance analysis by level designers
4724 R_Shadow_RenderMode_VisibleShadowVolumes();
4726 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4727 for (i = 0;i < numshadowentities;i++)
4728 R_Shadow_DrawEntityShadow(shadowentities[i]);
4729 for (i = 0;i < numshadowentities_noselfshadow;i++)
4730 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4731 R_Shadow_RenderMode_VisibleLighting(false, false);
4734 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4736 // optionally draw the illuminated areas
4737 // for performance analysis by level designers
4738 R_Shadow_RenderMode_VisibleLighting(false, false);
4740 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4741 for (i = 0;i < numlightentities;i++)
4742 R_Shadow_DrawEntityLight(lightentities[i]);
4743 for (i = 0;i < numlightentities_noselfshadow;i++)
4744 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4747 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4751 float shadowmapoffsetnoselfshadow = 0;
4752 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4753 Matrix4x4_Abs(&radiustolight);
4755 size = rtlight->shadowmapatlassidesize;
4756 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4758 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
4760 if (rtlight->cached_numshadowentities_noselfshadow)
4761 shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
4763 // render lighting using the depth texture as shadowmap
4764 // draw lighting in the unmasked areas
4765 if (numsurfaces + numlightentities)
4767 R_Shadow_RenderMode_Lighting(false, false, true, false);
4768 // draw lighting in the unmasked areas
4770 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4771 for (i = 0; i < numlightentities; i++)
4772 R_Shadow_DrawEntityLight(lightentities[i]);
4774 // offset to the noselfshadow part of the atlas and draw those too
4775 if (numlightentities_noselfshadow)
4777 R_Shadow_RenderMode_Lighting(false, false, true, true);
4778 for (i = 0; i < numlightentities_noselfshadow; i++)
4779 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4782 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
4783 if (r_shadow_usingdeferredprepass)
4784 R_Shadow_RenderMode_DrawDeferredLight(true);
4786 else if (castshadows && vid.stencil)
4788 // draw stencil shadow volumes to mask off pixels that are in shadow
4789 // so that they won't receive lighting
4790 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4791 R_Shadow_ClearStencil();
4794 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4795 for (i = 0;i < numshadowentities;i++)
4796 R_Shadow_DrawEntityShadow(shadowentities[i]);
4798 // draw lighting in the unmasked areas
4799 R_Shadow_RenderMode_Lighting(true, false, false, false);
4800 for (i = 0;i < numlightentities_noselfshadow;i++)
4801 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4803 for (i = 0;i < numshadowentities_noselfshadow;i++)
4804 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4806 // draw lighting in the unmasked areas
4807 R_Shadow_RenderMode_Lighting(true, false, false, false);
4809 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4810 for (i = 0;i < numlightentities;i++)
4811 R_Shadow_DrawEntityLight(lightentities[i]);
4813 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
4814 if (r_shadow_usingdeferredprepass)
4815 R_Shadow_RenderMode_DrawDeferredLight(false);
4819 // draw lighting in the unmasked areas
4820 R_Shadow_RenderMode_Lighting(false, false, false, false);
4822 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4823 for (i = 0;i < numlightentities;i++)
4824 R_Shadow_DrawEntityLight(lightentities[i]);
4825 for (i = 0;i < numlightentities_noselfshadow;i++)
4826 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4828 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
4829 if (r_shadow_usingdeferredprepass)
4830 R_Shadow_RenderMode_DrawDeferredLight(false);
4834 static void R_Shadow_FreeDeferred(void)
4836 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
4837 r_shadow_prepassgeometryfbo = 0;
4839 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
4840 r_shadow_prepasslightingdiffusespecularfbo = 0;
4842 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
4843 r_shadow_prepasslightingdiffusefbo = 0;
4845 if (r_shadow_prepassgeometrydepthbuffer)
4846 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
4847 r_shadow_prepassgeometrydepthbuffer = NULL;
4849 if (r_shadow_prepassgeometrynormalmaptexture)
4850 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4851 r_shadow_prepassgeometrynormalmaptexture = NULL;
4853 if (r_shadow_prepasslightingdiffusetexture)
4854 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
4855 r_shadow_prepasslightingdiffusetexture = NULL;
4857 if (r_shadow_prepasslightingspeculartexture)
4858 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4859 r_shadow_prepasslightingspeculartexture = NULL;
4862 void R_Shadow_DrawPrepass(void)
4866 entity_render_t *ent;
4867 float clearcolor[4];
4869 R_Mesh_ResetTextureState();
4871 GL_ColorMask(1,1,1,1);
4872 GL_BlendFunc(GL_ONE, GL_ZERO);
4875 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4876 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4877 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4878 if (r_timereport_active)
4879 R_TimeReport("prepasscleargeom");
4881 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4882 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4883 if (r_timereport_active)
4884 R_TimeReport("prepassworld");
4886 for (i = 0;i < r_refdef.scene.numentities;i++)
4888 if (!r_refdef.viewcache.entityvisible[i])
4890 ent = r_refdef.scene.entities[i];
4891 if (ent->model && ent->model->DrawPrepass != NULL)
4892 ent->model->DrawPrepass(ent);
4895 if (r_timereport_active)
4896 R_TimeReport("prepassmodels");
4898 GL_DepthMask(false);
4899 GL_ColorMask(1,1,1,1);
4902 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4903 Vector4Set(clearcolor, 0, 0, 0, 0);
4904 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4905 if (r_timereport_active)
4906 R_TimeReport("prepassclearlit");
4908 R_Shadow_RenderMode_Begin();
4910 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4911 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4913 R_Shadow_RenderMode_End();
4915 if (r_timereport_active)
4916 R_TimeReport("prepasslights");
4919 #define MAX_SCENELIGHTS 65536
4920 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
4922 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
4924 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
4926 r_shadow_scenemaxlights *= 2;
4927 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
4928 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
4930 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
4934 void R_Shadow_DrawLightSprites(void);
4935 void R_Shadow_PrepareLights(void)
4944 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
4945 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
4946 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
4948 if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
4949 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4950 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
4951 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4952 r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) ||
4953 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4954 r_shadow_shadowmapborder != shadowmapborder ||
4955 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
4956 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
4957 R_Shadow_FreeShadowMaps();
4959 r_shadow_usingshadowmaportho = false;
4961 switch (vid.renderpath)
4963 case RENDERPATH_GL20:
4965 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4967 r_shadow_usingdeferredprepass = false;
4968 if (r_shadow_prepass_width)
4969 R_Shadow_FreeDeferred();
4970 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4974 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4976 R_Shadow_FreeDeferred();
4978 r_shadow_usingdeferredprepass = true;
4979 r_shadow_prepass_width = vid.width;
4980 r_shadow_prepass_height = vid.height;
4981 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
4982 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);
4983 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);
4984 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);
4986 // set up the geometry pass fbo (depth + normalmap)
4987 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4988 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4989 // render depth into a renderbuffer and other important properties into the normalmap texture
4991 // set up the lighting pass fbo (diffuse + specular)
4992 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4993 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4994 // render diffuse into one texture and specular into another,
4995 // with depth and normalmap bound as textures,
4996 // with depth bound as attachment as well
4998 // set up the lighting pass fbo (diffuse)
4999 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5000 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5001 // render diffuse into one texture,
5002 // with depth and normalmap bound as textures,
5003 // with depth bound as attachment as well
5007 case RENDERPATH_GLES2:
5008 r_shadow_usingdeferredprepass = false;
5012 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);
5014 r_shadow_scenenumlights = 0;
5015 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5016 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5017 for (lightindex = 0; lightindex < range; lightindex++)
5019 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5020 if (light && (light->flags & flag))
5022 R_Shadow_PrepareLight(&light->rtlight);
5023 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5026 if (r_refdef.scene.rtdlight)
5028 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5030 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
5031 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
5034 else if (gl_flashblend.integer)
5036 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5038 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
5039 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
5040 VectorScale(rtlight->color, f, rtlight->currentcolor);
5044 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
5045 if (r_shadow_debuglight.integer >= 0)
5047 r_shadow_scenenumlights = 0;
5048 lightindex = r_shadow_debuglight.integer;
5049 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5052 R_Shadow_PrepareLight(&light->rtlight);
5053 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5057 // if we're doing shadowmaps we need to prepare the atlas layout now
5058 if (R_Shadow_ShadowMappingEnabled())
5062 // allocate shadowmaps in the atlas now
5063 // 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...
5064 for (lod = 0; lod < 16; lod++)
5066 int packing_success = 0;
5067 int packing_failure = 0;
5068 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
5069 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
5070 if (r_shadow_shadowmapatlas_modelshadows_size)
5071 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);
5072 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5074 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
5075 int size = rtlight->shadowmapsidesize >> lod;
5077 if (!rtlight->castshadows)
5079 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
5082 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
5083 if (rtlight->cached_numshadowentities_noselfshadow)
5085 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
5087 rtlight->shadowmapatlassidesize = size;
5092 // note down that we failed to pack this one, it will have to disable shadows
5093 rtlight->shadowmapatlassidesize = 0;
5097 // generally everything fits and we stop here on the first iteration
5098 if (packing_failure == 0)
5103 if (r_editlights.integer)
5104 R_Shadow_DrawLightSprites();
5107 void R_Shadow_DrawShadowMaps(void)
5109 R_Shadow_RenderMode_Begin();
5110 R_Shadow_RenderMode_ActiveLight(NULL);
5112 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
5113 R_Shadow_ClearShadowMapTexture();
5115 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
5116 if (r_shadow_shadowmapatlas_modelshadows_size)
5118 R_Shadow_DrawModelShadowMaps();
5119 // don't let sound skip if going slow
5120 if (r_refdef.scene.extraupdate)
5124 if (R_Shadow_ShadowMappingEnabled())
5127 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5128 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
5131 R_Shadow_RenderMode_End();
5134 void R_Shadow_DrawLights(void)
5138 R_Shadow_RenderMode_Begin();
5140 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5141 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5143 R_Shadow_RenderMode_End();
5146 #define MAX_MODELSHADOWS 1024
5147 static int r_shadow_nummodelshadows;
5148 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
5150 void R_Shadow_PrepareModelShadows(void)
5153 float scale, size, radius, dot1, dot2;
5154 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5155 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
5156 entity_render_t *ent;
5158 r_shadow_nummodelshadows = 0;
5159 r_shadow_shadowmapatlas_modelshadows_size = 0;
5161 if (!r_refdef.scene.numentities || r_refdef.scene.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
5164 switch (r_shadow_shadowmode)
5166 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
5167 if (r_shadows.integer >= 2)
5170 case R_SHADOW_SHADOWMODE_STENCIL:
5173 for (i = 0; i < r_refdef.scene.numentities; i++)
5175 ent = r_refdef.scene.entities[i];
5176 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5178 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5180 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5181 R_AnimCache_GetEntity(ent, false, false);
5189 size = r_shadow_shadowmaptexturesize / 4;
5190 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
5191 radius = 0.5f * size / scale;
5193 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5194 VectorCopy(prvmshadowdir, shadowdir);
5195 VectorNormalize(shadowdir);
5196 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5197 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5198 if (fabs(dot1) <= fabs(dot2))
5199 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5201 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5202 VectorNormalize(shadowforward);
5203 CrossProduct(shadowdir, shadowforward, shadowright);
5204 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5205 VectorCopy(prvmshadowfocus, shadowfocus);
5206 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5207 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5208 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5209 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5210 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5212 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5214 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5215 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5216 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5217 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5218 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5219 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5221 for (i = 0; i < r_refdef.scene.numentities; i++)
5223 ent = r_refdef.scene.entities[i];
5224 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
5226 // cast shadows from anything of the map (submodels are optional)
5227 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5229 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5231 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5232 R_AnimCache_GetEntity(ent, false, false);
5236 if (r_shadow_nummodelshadows)
5238 r_shadow_shadowmapatlas_modelshadows_x = 0;
5239 r_shadow_shadowmapatlas_modelshadows_y = 0;
5240 r_shadow_shadowmapatlas_modelshadows_size = size;
5244 static void R_Shadow_DrawModelShadowMaps(void)
5247 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
5248 entity_render_t *ent;
5249 vec3_t relativelightorigin;
5250 vec3_t relativelightdirection, relativeforward, relativeright;
5251 vec3_t relativeshadowmins, relativeshadowmaxs;
5252 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
5253 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5255 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
5256 r_viewport_t viewport;
5258 size = r_shadow_shadowmapatlas_modelshadows_size;
5259 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
5260 radius = 0.5f / scale;
5261 nearclip = -r_shadows_throwdistance.value;
5262 farclip = r_shadows_throwdistance.value;
5263 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);
5265 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
5266 r_shadow_modelshadowmap_parameters[0] = size;
5267 r_shadow_modelshadowmap_parameters[1] = size;
5268 r_shadow_modelshadowmap_parameters[2] = 1.0;
5269 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
5270 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
5271 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
5272 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
5273 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
5274 r_shadow_usingshadowmaportho = true;
5276 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5277 VectorCopy(prvmshadowdir, shadowdir);
5278 VectorNormalize(shadowdir);
5279 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5280 VectorCopy(prvmshadowfocus, shadowfocus);
5281 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5282 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5283 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5284 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5285 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5286 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5287 if (fabs(dot1) <= fabs(dot2))
5288 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5290 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5291 VectorNormalize(shadowforward);
5292 VectorM(scale, shadowforward, &m[0]);
5293 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5295 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
5296 CrossProduct(shadowdir, shadowforward, shadowright);
5297 VectorM(scale, shadowright, &m[4]);
5298 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
5299 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
5300 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
5301 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
5302 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
5303 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);
5304 R_SetViewport(&viewport);
5306 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5308 // render into a slightly restricted region so that the borders of the
5309 // shadowmap area fade away, rather than streaking across everything
5310 // outside the usable area
5311 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
5313 for (i = 0;i < r_shadow_nummodelshadows;i++)
5315 ent = r_shadow_modelshadows[i];
5316 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5317 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
5318 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5319 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
5320 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
5321 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5322 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5323 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5324 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5325 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5326 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5327 RSurf_ActiveModelEntity(ent, false, false, false);
5328 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
5329 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5335 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
5337 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
5339 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
5340 Cvar_SetValueQuick(&r_test, 0);
5345 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
5346 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
5347 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
5348 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
5349 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
5350 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
5353 void R_Shadow_DrawModelShadows(void)
5356 float relativethrowdistance;
5357 entity_render_t *ent;
5358 vec3_t relativelightorigin;
5359 vec3_t relativelightdirection;
5360 vec3_t relativeshadowmins, relativeshadowmaxs;
5361 vec3_t tmp, shadowdir;
5362 prvm_vec3_t prvmshadowdir;
5364 if (!r_shadow_nummodelshadows || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
5367 R_ResetViewRendering3D(r_shadow_viewfbo, r_shadow_viewdepthtexture, r_shadow_viewcolortexture, r_shadow_viewx, r_shadow_viewy, r_shadow_viewwidth, r_shadow_viewheight);
5368 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
5369 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5370 R_Shadow_RenderMode_Begin();
5371 R_Shadow_RenderMode_ActiveLight(NULL);
5372 r_shadow_lightscissor[0] = r_shadow_viewx;
5373 r_shadow_lightscissor[1] = (r_shadow_viewfbo ? r_shadow_viewheight : vid.height) - r_shadow_viewy - r_shadow_viewheight;
5374 r_shadow_lightscissor[2] = r_shadow_viewwidth;
5375 r_shadow_lightscissor[3] = r_shadow_viewheight;
5376 R_Shadow_RenderMode_StencilShadowVolumes(false);
5379 if (r_shadows.integer == 2)
5381 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5382 VectorCopy(prvmshadowdir, shadowdir);
5383 VectorNormalize(shadowdir);
5386 R_Shadow_ClearStencil();
5388 for (i = 0;i < r_shadow_nummodelshadows;i++)
5390 ent = r_shadow_modelshadows[i];
5392 // cast shadows from anything of the map (submodels are optional)
5393 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5394 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
5395 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
5396 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
5397 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5400 VectorNegate(ent->render_modellight_lightdir, tmp);
5401 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
5404 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
5405 RSurf_ActiveModelEntity(ent, false, false, false);
5406 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
5407 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5410 // not really the right mode, but this will disable any silly stencil features
5411 R_Shadow_RenderMode_End();
5413 // set up ortho view for rendering this pass
5414 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5415 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5416 //GL_ScissorTest(true);
5417 //R_EntityMatrix(&identitymatrix);
5418 //R_Mesh_ResetTextureState();
5419 R_ResetViewRendering2D(r_shadow_viewfbo, r_shadow_viewdepthtexture, r_shadow_viewcolortexture, r_shadow_viewx, r_shadow_viewy, r_shadow_viewwidth, r_shadow_viewheight);
5421 // set up a darkening blend on shadowed areas
5422 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5423 //GL_DepthRange(0, 1);
5424 //GL_DepthTest(false);
5425 //GL_DepthMask(false);
5426 //GL_PolygonOffset(0, 0);CHECKGLERROR
5427 GL_Color(0, 0, 0, r_shadows_darken.value);
5428 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5429 //GL_DepthFunc(GL_ALWAYS);
5430 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5432 // apply the blend to the shadowed areas
5433 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5434 R_SetupShader_Generic_NoTexture(false, true);
5435 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5437 // restore the viewport
5438 R_SetViewport(&r_refdef.view.viewport);
5440 // restore other state to normal
5441 //R_Shadow_RenderMode_End();
5444 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5447 vec3_t centerorigin;
5448 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5451 // if it's too close, skip it
5452 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5454 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5457 if (usequery && r_numqueries + 2 <= r_maxqueries)
5459 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5460 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5461 // 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
5462 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5464 switch(vid.renderpath)
5466 case RENDERPATH_GL20:
5467 case RENDERPATH_GLES2:
5468 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5470 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5471 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5472 GL_DepthFunc(GL_ALWAYS);
5473 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5474 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5475 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5476 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5477 GL_DepthFunc(GL_LEQUAL);
5478 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5479 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5480 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5481 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5482 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5488 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5491 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5493 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5496 unsigned int occlude = 0;
5497 GLint allpixels = 0, visiblepixels = 0;
5499 // now we have to check the query result
5500 if (rtlight->corona_queryindex_visiblepixels)
5502 switch(vid.renderpath)
5504 case RENDERPATH_GL20:
5505 case RENDERPATH_GLES2:
5506 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5507 // See if we can use the GPU-side method to prevent implicit sync
5508 if (vid.support.arb_query_buffer_object) {
5509 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
5510 if (!r_shadow_occlusion_buf) {
5511 qglGenBuffersARB(1, &r_shadow_occlusion_buf);
5512 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5513 qglBufferDataARB(GL_QUERY_BUFFER_ARB, 8, NULL, GL_DYNAMIC_COPY);
5515 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5517 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(0));
5518 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4));
5519 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
5520 occlude = MATERIALFLAG_OCCLUDE;
5521 cscale *= rtlight->corona_visibility;
5526 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5527 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5528 if (visiblepixels < 1 || allpixels < 1)
5530 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5531 cscale *= rtlight->corona_visibility;
5541 if (CL_Cache_TraceLineSurfaces(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT).fraction < 1)
5544 VectorScale(rtlight->currentcolor, cscale, color);
5545 if (VectorLength(color) > (1.0f / 256.0f))
5548 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
5551 VectorNegate(color, color);
5552 GL_BlendEquationSubtract(true);
5554 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5555 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);
5556 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
5558 GL_BlendEquationSubtract(false);
5562 void R_Shadow_DrawCoronas(void)
5565 qboolean usequery = false;
5570 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
5572 if (r_fb.water.renderingscene)
5574 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5575 R_EntityMatrix(&identitymatrix);
5577 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5579 // check occlusion of coronas
5580 // use GL_ARB_occlusion_query if available
5581 // otherwise use raytraces
5583 switch (vid.renderpath)
5585 case RENDERPATH_GL20:
5586 case RENDERPATH_GLES2:
5587 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
5588 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5591 GL_ColorMask(0,0,0,0);
5592 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
5593 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
5596 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
5597 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
5599 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
5602 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
5603 GL_BlendFunc(GL_ONE, GL_ZERO);
5604 GL_CullFace(GL_NONE);
5605 GL_DepthMask(false);
5606 GL_DepthRange(0, 1);
5607 GL_PolygonOffset(0, 0);
5609 R_Mesh_ResetTextureState();
5610 R_SetupShader_Generic_NoTexture(false, false);
5615 for (lightindex = 0;lightindex < range;lightindex++)
5617 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5620 rtlight = &light->rtlight;
5621 rtlight->corona_visibility = 0;
5622 rtlight->corona_queryindex_visiblepixels = 0;
5623 rtlight->corona_queryindex_allpixels = 0;
5624 if (!(rtlight->flags & flag))
5626 if (rtlight->corona <= 0)
5628 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
5630 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5632 for (i = 0;i < r_refdef.scene.numlights;i++)
5634 rtlight = r_refdef.scene.lights[i];
5635 rtlight->corona_visibility = 0;
5636 rtlight->corona_queryindex_visiblepixels = 0;
5637 rtlight->corona_queryindex_allpixels = 0;
5638 if (!(rtlight->flags & flag))
5640 if (rtlight->corona <= 0)
5642 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5645 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5647 // now draw the coronas using the query data for intensity info
5648 for (lightindex = 0;lightindex < range;lightindex++)
5650 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5653 rtlight = &light->rtlight;
5654 if (rtlight->corona_visibility <= 0)
5656 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5658 for (i = 0;i < r_refdef.scene.numlights;i++)
5660 rtlight = r_refdef.scene.lights[i];
5661 if (rtlight->corona_visibility <= 0)
5663 if (gl_flashblend.integer)
5664 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
5666 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5672 static dlight_t *R_Shadow_NewWorldLight(void)
5674 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
5677 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)
5681 // 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
5683 // validate parameters
5687 // copy to light properties
5688 VectorCopy(origin, light->origin);
5689 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
5690 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
5691 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
5693 light->color[0] = max(color[0], 0);
5694 light->color[1] = max(color[1], 0);
5695 light->color[2] = max(color[2], 0);
5697 light->color[0] = color[0];
5698 light->color[1] = color[1];
5699 light->color[2] = color[2];
5700 light->radius = max(radius, 0);
5701 light->style = style;
5702 light->shadow = shadowenable;
5703 light->corona = corona;
5704 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
5705 light->coronasizescale = coronasizescale;
5706 light->ambientscale = ambientscale;
5707 light->diffusescale = diffusescale;
5708 light->specularscale = specularscale;
5709 light->flags = flags;
5711 // update renderable light data
5712 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
5713 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);
5716 static void R_Shadow_FreeWorldLight(dlight_t *light)
5718 if (r_shadow_selectedlight == light)
5719 r_shadow_selectedlight = NULL;
5720 R_RTLight_Uncompile(&light->rtlight);
5721 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
5724 void R_Shadow_ClearWorldLights(void)
5728 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5729 for (lightindex = 0;lightindex < range;lightindex++)
5731 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5733 R_Shadow_FreeWorldLight(light);
5735 r_shadow_selectedlight = NULL;
5738 static void R_Shadow_SelectLight(dlight_t *light)
5740 if (r_shadow_selectedlight)
5741 r_shadow_selectedlight->selected = false;
5742 r_shadow_selectedlight = light;
5743 if (r_shadow_selectedlight)
5744 r_shadow_selectedlight->selected = true;
5747 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5749 // this is never batched (there can be only one)
5751 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
5752 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5753 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5756 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5761 skinframe_t *skinframe;
5764 // this is never batched (due to the ent parameter changing every time)
5765 // so numsurfaces == 1 and surfacelist[0] == lightnumber
5766 const dlight_t *light = (dlight_t *)ent;
5769 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
5772 VectorScale(light->color, intensity, spritecolor);
5773 if (VectorLength(spritecolor) < 0.1732f)
5774 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
5775 if (VectorLength(spritecolor) > 1.0f)
5776 VectorNormalize(spritecolor);
5778 // draw light sprite
5779 if (light->cubemapname[0] && !light->shadow)
5780 skinframe = r_editlights_sprcubemapnoshadowlight;
5781 else if (light->cubemapname[0])
5782 skinframe = r_editlights_sprcubemaplight;
5783 else if (!light->shadow)
5784 skinframe = r_editlights_sprnoshadowlight;
5786 skinframe = r_editlights_sprlight;
5788 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);
5789 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5791 // draw selection sprite if light is selected
5792 if (light->selected)
5794 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5795 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5796 // VorteX todo: add normalmode/realtime mode light overlay sprites?
5800 void R_Shadow_DrawLightSprites(void)
5804 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5805 for (lightindex = 0;lightindex < range;lightindex++)
5807 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5809 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
5811 if (!r_editlights_lockcursor)
5812 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
5815 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
5820 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
5821 if (lightindex >= range)
5823 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5826 rtlight = &light->rtlight;
5827 //if (!(rtlight->flags & flag))
5829 VectorCopy(rtlight->shadoworigin, origin);
5830 *radius = rtlight->radius;
5831 VectorCopy(rtlight->color, color);
5835 static void R_Shadow_SelectLightInView(void)
5837 float bestrating, rating, temp[3];
5841 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5845 if (r_editlights_lockcursor)
5847 for (lightindex = 0;lightindex < range;lightindex++)
5849 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5852 VectorSubtract(light->origin, r_refdef.view.origin, temp);
5853 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
5856 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
5857 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)
5859 bestrating = rating;
5864 R_Shadow_SelectLight(best);
5867 void R_Shadow_LoadWorldLights(void)
5869 int n, a, style, shadow, flags;
5870 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
5871 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
5872 if (cl.worldmodel == NULL)
5874 Con_Print("No map loaded.\n");
5877 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5878 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5888 for (;COM_Parse(t, true) && strcmp(
5889 if (COM_Parse(t, true))
5891 if (com_token[0] == '!')
5894 origin[0] = atof(com_token+1);
5897 origin[0] = atof(com_token);
5902 while (*s && *s != '\n' && *s != '\r')
5908 // check for modifier flags
5915 #if _MSC_VER >= 1400
5916 #define sscanf sscanf_s
5918 cubemapname[sizeof(cubemapname)-1] = 0;
5919 #if MAX_QPATH != 128
5920 #error update this code if MAX_QPATH changes
5922 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
5923 #if _MSC_VER >= 1400
5924 , sizeof(cubemapname)
5926 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5929 flags = LIGHTFLAG_REALTIMEMODE;
5937 coronasizescale = 0.25f;
5939 VectorClear(angles);
5942 if (a < 9 || !strcmp(cubemapname, "\"\""))
5944 // remove quotes on cubemapname
5945 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5948 namelen = strlen(cubemapname) - 2;
5949 memmove(cubemapname, cubemapname + 1, namelen);
5950 cubemapname[namelen] = '\0';
5954 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);
5957 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5965 Con_Printf("invalid rtlights file \"%s\"\n", name);
5966 Mem_Free(lightsstring);
5970 void R_Shadow_SaveWorldLights(void)
5974 size_t bufchars, bufmaxchars;
5976 char name[MAX_QPATH];
5977 char line[MAX_INPUTLINE];
5978 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5979 // I hate lines which are 3 times my screen size :( --blub
5982 if (cl.worldmodel == NULL)
5984 Con_Print("No map loaded.\n");
5987 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5988 bufchars = bufmaxchars = 0;
5990 for (lightindex = 0;lightindex < range;lightindex++)
5992 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5995 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5996 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);
5997 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5998 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]);
6000 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);
6001 if (bufchars + strlen(line) > bufmaxchars)
6003 bufmaxchars = bufchars + strlen(line) + 2048;
6005 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
6009 memcpy(buf, oldbuf, bufchars);
6015 memcpy(buf + bufchars, line, strlen(line));
6016 bufchars += strlen(line);
6020 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
6025 void R_Shadow_LoadLightsFile(void)
6028 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
6029 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
6030 if (cl.worldmodel == NULL)
6032 Con_Print("No map loaded.\n");
6035 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
6036 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6044 while (*s && *s != '\n' && *s != '\r')
6050 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);
6054 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);
6057 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
6058 radius = bound(15, radius, 4096);
6059 VectorScale(color, (2.0f / (8388608.0f)), color);
6060 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6068 Con_Printf("invalid lights file \"%s\"\n", name);
6069 Mem_Free(lightsstring);
6073 // tyrlite/hmap2 light types in the delay field
6074 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
6076 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
6088 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
6089 char key[256], value[MAX_INPUTLINE];
6092 if (cl.worldmodel == NULL)
6094 Con_Print("No map loaded.\n");
6097 // try to load a .ent file first
6098 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
6099 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
6100 // and if that is not found, fall back to the bsp file entity string
6102 data = cl.worldmodel->brush.entities;
6105 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
6107 type = LIGHTTYPE_MINUSX;
6108 origin[0] = origin[1] = origin[2] = 0;
6109 originhack[0] = originhack[1] = originhack[2] = 0;
6110 angles[0] = angles[1] = angles[2] = 0;
6111 color[0] = color[1] = color[2] = 1;
6112 light[0] = light[1] = light[2] = 1;light[3] = 300;
6113 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
6123 if (!COM_ParseToken_Simple(&data, false, false, true))
6125 if (com_token[0] == '}')
6126 break; // end of entity
6127 if (com_token[0] == '_')
6128 strlcpy(key, com_token + 1, sizeof(key));
6130 strlcpy(key, com_token, sizeof(key));
6131 while (key[strlen(key)-1] == ' ') // remove trailing spaces
6132 key[strlen(key)-1] = 0;
6133 if (!COM_ParseToken_Simple(&data, false, false, true))
6135 strlcpy(value, com_token, sizeof(value));
6137 // now that we have the key pair worked out...
6138 if (!strcmp("light", key))
6140 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
6144 light[0] = vec[0] * (1.0f / 256.0f);
6145 light[1] = vec[0] * (1.0f / 256.0f);
6146 light[2] = vec[0] * (1.0f / 256.0f);
6152 light[0] = vec[0] * (1.0f / 255.0f);
6153 light[1] = vec[1] * (1.0f / 255.0f);
6154 light[2] = vec[2] * (1.0f / 255.0f);
6158 else if (!strcmp("delay", key))
6160 else if (!strcmp("origin", key))
6161 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
6162 else if (!strcmp("angle", key))
6163 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
6164 else if (!strcmp("angles", key))
6165 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
6166 else if (!strcmp("color", key))
6167 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
6168 else if (!strcmp("wait", key))
6169 fadescale = atof(value);
6170 else if (!strcmp("classname", key))
6172 if (!strncmp(value, "light", 5))
6175 if (!strcmp(value, "light_fluoro"))
6180 overridecolor[0] = 1;
6181 overridecolor[1] = 1;
6182 overridecolor[2] = 1;
6184 if (!strcmp(value, "light_fluorospark"))
6189 overridecolor[0] = 1;
6190 overridecolor[1] = 1;
6191 overridecolor[2] = 1;
6193 if (!strcmp(value, "light_globe"))
6198 overridecolor[0] = 1;
6199 overridecolor[1] = 0.8;
6200 overridecolor[2] = 0.4;
6202 if (!strcmp(value, "light_flame_large_yellow"))
6207 overridecolor[0] = 1;
6208 overridecolor[1] = 0.5;
6209 overridecolor[2] = 0.1;
6211 if (!strcmp(value, "light_flame_small_yellow"))
6216 overridecolor[0] = 1;
6217 overridecolor[1] = 0.5;
6218 overridecolor[2] = 0.1;
6220 if (!strcmp(value, "light_torch_small_white"))
6225 overridecolor[0] = 1;
6226 overridecolor[1] = 0.5;
6227 overridecolor[2] = 0.1;
6229 if (!strcmp(value, "light_torch_small_walltorch"))
6234 overridecolor[0] = 1;
6235 overridecolor[1] = 0.5;
6236 overridecolor[2] = 0.1;
6240 else if (!strcmp("style", key))
6241 style = atoi(value);
6242 else if (!strcmp("skin", key))
6243 skin = (int)atof(value);
6244 else if (!strcmp("pflags", key))
6245 pflags = (int)atof(value);
6246 //else if (!strcmp("effects", key))
6247 // effects = (int)atof(value);
6248 else if (cl.worldmodel->type == mod_brushq3)
6250 if (!strcmp("scale", key))
6251 lightscale = atof(value);
6252 if (!strcmp("fade", key))
6253 fadescale = atof(value);
6258 if (lightscale <= 0)
6262 if (color[0] == color[1] && color[0] == color[2])
6264 color[0] *= overridecolor[0];
6265 color[1] *= overridecolor[1];
6266 color[2] *= overridecolor[2];
6268 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
6269 color[0] = color[0] * light[0];
6270 color[1] = color[1] * light[1];
6271 color[2] = color[2] * light[2];
6274 case LIGHTTYPE_MINUSX:
6276 case LIGHTTYPE_RECIPX:
6278 VectorScale(color, (1.0f / 16.0f), color);
6280 case LIGHTTYPE_RECIPXX:
6282 VectorScale(color, (1.0f / 16.0f), color);
6285 case LIGHTTYPE_NONE:
6289 case LIGHTTYPE_MINUSXX:
6292 VectorAdd(origin, originhack, origin);
6294 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);
6297 Mem_Free(entfiledata);
6301 static void R_Shadow_SetCursorLocationForView(void)
6304 vec3_t dest, endpos;
6306 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
6307 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
6308 if (trace.fraction < 1)
6310 dist = trace.fraction * r_editlights_cursordistance.value;
6311 push = r_editlights_cursorpushback.value;
6315 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
6316 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
6320 VectorClear( endpos );
6322 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6323 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6324 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6327 void R_Shadow_UpdateWorldLightSelection(void)
6329 if (r_editlights.integer)
6331 R_Shadow_SetCursorLocationForView();
6332 R_Shadow_SelectLightInView();
6335 R_Shadow_SelectLight(NULL);
6338 static void R_Shadow_EditLights_Clear_f(void)
6340 R_Shadow_ClearWorldLights();
6343 void R_Shadow_EditLights_Reload_f(void)
6347 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
6348 R_Shadow_ClearWorldLights();
6349 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
6351 R_Shadow_LoadWorldLights();
6352 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6353 R_Shadow_LoadLightsFile();
6355 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
6357 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6358 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6362 static void R_Shadow_EditLights_Save_f(void)
6366 R_Shadow_SaveWorldLights();
6369 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6371 R_Shadow_ClearWorldLights();
6372 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6375 static void R_Shadow_EditLights_ImportLightsFile_f(void)
6377 R_Shadow_ClearWorldLights();
6378 R_Shadow_LoadLightsFile();
6381 static void R_Shadow_EditLights_Spawn_f(void)
6384 if (!r_editlights.integer)
6386 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6389 if (Cmd_Argc() != 1)
6391 Con_Print("r_editlights_spawn does not take parameters\n");
6394 color[0] = color[1] = color[2] = 1;
6395 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6398 static void R_Shadow_EditLights_Edit_f(void)
6400 vec3_t origin, angles, color;
6401 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6402 int style, shadows, flags, normalmode, realtimemode;
6403 char cubemapname[MAX_INPUTLINE];
6404 if (!r_editlights.integer)
6406 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6409 if (!r_shadow_selectedlight)
6411 Con_Print("No selected light.\n");
6414 VectorCopy(r_shadow_selectedlight->origin, origin);
6415 VectorCopy(r_shadow_selectedlight->angles, angles);
6416 VectorCopy(r_shadow_selectedlight->color, color);
6417 radius = r_shadow_selectedlight->radius;
6418 style = r_shadow_selectedlight->style;
6419 if (r_shadow_selectedlight->cubemapname)
6420 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6423 shadows = r_shadow_selectedlight->shadow;
6424 corona = r_shadow_selectedlight->corona;
6425 coronasizescale = r_shadow_selectedlight->coronasizescale;
6426 ambientscale = r_shadow_selectedlight->ambientscale;
6427 diffusescale = r_shadow_selectedlight->diffusescale;
6428 specularscale = r_shadow_selectedlight->specularscale;
6429 flags = r_shadow_selectedlight->flags;
6430 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6431 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6432 if (!strcmp(Cmd_Argv(1), "origin"))
6434 if (Cmd_Argc() != 5)
6436 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6439 origin[0] = atof(Cmd_Argv(2));
6440 origin[1] = atof(Cmd_Argv(3));
6441 origin[2] = atof(Cmd_Argv(4));
6443 else if (!strcmp(Cmd_Argv(1), "originscale"))
6445 if (Cmd_Argc() != 5)
6447 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6450 origin[0] *= atof(Cmd_Argv(2));
6451 origin[1] *= atof(Cmd_Argv(3));
6452 origin[2] *= atof(Cmd_Argv(4));
6454 else if (!strcmp(Cmd_Argv(1), "originx"))
6456 if (Cmd_Argc() != 3)
6458 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6461 origin[0] = atof(Cmd_Argv(2));
6463 else if (!strcmp(Cmd_Argv(1), "originy"))
6465 if (Cmd_Argc() != 3)
6467 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6470 origin[1] = atof(Cmd_Argv(2));
6472 else if (!strcmp(Cmd_Argv(1), "originz"))
6474 if (Cmd_Argc() != 3)
6476 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6479 origin[2] = atof(Cmd_Argv(2));
6481 else if (!strcmp(Cmd_Argv(1), "move"))
6483 if (Cmd_Argc() != 5)
6485 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6488 origin[0] += atof(Cmd_Argv(2));
6489 origin[1] += atof(Cmd_Argv(3));
6490 origin[2] += atof(Cmd_Argv(4));
6492 else if (!strcmp(Cmd_Argv(1), "movex"))
6494 if (Cmd_Argc() != 3)
6496 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6499 origin[0] += atof(Cmd_Argv(2));
6501 else if (!strcmp(Cmd_Argv(1), "movey"))
6503 if (Cmd_Argc() != 3)
6505 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6508 origin[1] += atof(Cmd_Argv(2));
6510 else if (!strcmp(Cmd_Argv(1), "movez"))
6512 if (Cmd_Argc() != 3)
6514 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6517 origin[2] += atof(Cmd_Argv(2));
6519 else if (!strcmp(Cmd_Argv(1), "angles"))
6521 if (Cmd_Argc() != 5)
6523 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6526 angles[0] = atof(Cmd_Argv(2));
6527 angles[1] = atof(Cmd_Argv(3));
6528 angles[2] = atof(Cmd_Argv(4));
6530 else if (!strcmp(Cmd_Argv(1), "anglesx"))
6532 if (Cmd_Argc() != 3)
6534 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6537 angles[0] = atof(Cmd_Argv(2));
6539 else if (!strcmp(Cmd_Argv(1), "anglesy"))
6541 if (Cmd_Argc() != 3)
6543 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6546 angles[1] = atof(Cmd_Argv(2));
6548 else if (!strcmp(Cmd_Argv(1), "anglesz"))
6550 if (Cmd_Argc() != 3)
6552 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6555 angles[2] = atof(Cmd_Argv(2));
6557 else if (!strcmp(Cmd_Argv(1), "color"))
6559 if (Cmd_Argc() != 5)
6561 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
6564 color[0] = atof(Cmd_Argv(2));
6565 color[1] = atof(Cmd_Argv(3));
6566 color[2] = atof(Cmd_Argv(4));
6568 else if (!strcmp(Cmd_Argv(1), "radius"))
6570 if (Cmd_Argc() != 3)
6572 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6575 radius = atof(Cmd_Argv(2));
6577 else if (!strcmp(Cmd_Argv(1), "colorscale"))
6579 if (Cmd_Argc() == 3)
6581 double scale = atof(Cmd_Argv(2));
6588 if (Cmd_Argc() != 5)
6590 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
6593 color[0] *= atof(Cmd_Argv(2));
6594 color[1] *= atof(Cmd_Argv(3));
6595 color[2] *= atof(Cmd_Argv(4));
6598 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
6600 if (Cmd_Argc() != 3)
6602 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6605 radius *= atof(Cmd_Argv(2));
6607 else if (!strcmp(Cmd_Argv(1), "style"))
6609 if (Cmd_Argc() != 3)
6611 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6614 style = atoi(Cmd_Argv(2));
6616 else if (!strcmp(Cmd_Argv(1), "cubemap"))
6620 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6623 if (Cmd_Argc() == 3)
6624 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
6628 else if (!strcmp(Cmd_Argv(1), "shadows"))
6630 if (Cmd_Argc() != 3)
6632 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6635 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6637 else if (!strcmp(Cmd_Argv(1), "corona"))
6639 if (Cmd_Argc() != 3)
6641 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6644 corona = atof(Cmd_Argv(2));
6646 else if (!strcmp(Cmd_Argv(1), "coronasize"))
6648 if (Cmd_Argc() != 3)
6650 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6653 coronasizescale = atof(Cmd_Argv(2));
6655 else if (!strcmp(Cmd_Argv(1), "ambient"))
6657 if (Cmd_Argc() != 3)
6659 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6662 ambientscale = atof(Cmd_Argv(2));
6664 else if (!strcmp(Cmd_Argv(1), "diffuse"))
6666 if (Cmd_Argc() != 3)
6668 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6671 diffusescale = atof(Cmd_Argv(2));
6673 else if (!strcmp(Cmd_Argv(1), "specular"))
6675 if (Cmd_Argc() != 3)
6677 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6680 specularscale = atof(Cmd_Argv(2));
6682 else if (!strcmp(Cmd_Argv(1), "normalmode"))
6684 if (Cmd_Argc() != 3)
6686 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6689 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6691 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
6693 if (Cmd_Argc() != 3)
6695 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6698 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6702 Con_Print("usage: r_editlights_edit [property] [value]\n");
6703 Con_Print("Selected light's properties:\n");
6704 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6705 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6706 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6707 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
6708 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
6709 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
6710 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
6711 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
6712 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
6713 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
6714 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
6715 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
6716 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
6717 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
6720 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
6721 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6724 static void R_Shadow_EditLights_EditAll_f(void)
6727 dlight_t *light, *oldselected;
6730 if (!r_editlights.integer)
6732 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
6736 oldselected = r_shadow_selectedlight;
6737 // EditLights doesn't seem to have a "remove" command or something so:
6738 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6739 for (lightindex = 0;lightindex < range;lightindex++)
6741 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6744 R_Shadow_SelectLight(light);
6745 R_Shadow_EditLights_Edit_f();
6747 // return to old selected (to not mess editing once selection is locked)
6748 R_Shadow_SelectLight(oldselected);
6751 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
6753 int lightnumber, lightcount;
6754 size_t lightindex, range;
6759 if (!r_editlights.integer)
6762 // update cvars so QC can query them
6763 if (r_shadow_selectedlight)
6765 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6766 Cvar_SetQuick(&r_editlights_current_origin, temp);
6767 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6768 Cvar_SetQuick(&r_editlights_current_angles, temp);
6769 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6770 Cvar_SetQuick(&r_editlights_current_color, temp);
6771 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
6772 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
6773 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
6774 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
6775 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
6776 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
6777 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
6778 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
6779 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
6780 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
6781 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
6784 // draw properties on screen
6785 if (!r_editlights_drawproperties.integer)
6787 x = vid_conwidth.value - 320;
6789 DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
6792 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6793 for (lightindex = 0;lightindex < range;lightindex++)
6795 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6798 if (light == r_shadow_selectedlight)
6799 lightnumber = (int)lightindex;
6802 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;
6803 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;
6805 if (r_shadow_selectedlight == NULL)
6807 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;
6808 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;
6809 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;
6810 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;
6811 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;
6812 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;
6813 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;
6814 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;
6815 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;
6816 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;
6817 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;
6818 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;
6819 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;
6820 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;
6821 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;
6823 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;
6824 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;
6825 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;
6826 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;
6827 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;
6828 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;
6829 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;
6830 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;
6831 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;
6832 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;
6835 static void R_Shadow_EditLights_ToggleShadow_f(void)
6837 if (!r_editlights.integer)
6839 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6842 if (!r_shadow_selectedlight)
6844 Con_Print("No selected light.\n");
6847 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);
6850 static void R_Shadow_EditLights_ToggleCorona_f(void)
6852 if (!r_editlights.integer)
6854 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6857 if (!r_shadow_selectedlight)
6859 Con_Print("No selected light.\n");
6862 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);
6865 static void R_Shadow_EditLights_Remove_f(void)
6867 if (!r_editlights.integer)
6869 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
6872 if (!r_shadow_selectedlight)
6874 Con_Print("No selected light.\n");
6877 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
6878 r_shadow_selectedlight = NULL;
6881 static void R_Shadow_EditLights_Help_f(void)
6884 "Documentation on r_editlights system:\n"
6886 "r_editlights : enable/disable editing mode\n"
6887 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
6888 "r_editlights_cursorpushback : push back cursor this far from surface\n"
6889 "r_editlights_cursorpushoff : push cursor off surface this far\n"
6890 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
6891 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
6893 "r_editlights_help : this help\n"
6894 "r_editlights_clear : remove all lights\n"
6895 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
6896 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
6897 "r_editlights_save : save to .rtlights file\n"
6898 "r_editlights_spawn : create a light with default settings\n"
6899 "r_editlights_edit command : edit selected light - more documentation below\n"
6900 "r_editlights_remove : remove selected light\n"
6901 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
6902 "r_editlights_importlightentitiesfrommap : reload light entities\n"
6903 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
6905 "origin x y z : set light location\n"
6906 "originx x: set x component of light location\n"
6907 "originy y: set y component of light location\n"
6908 "originz z: set z component of light location\n"
6909 "move x y z : adjust light location\n"
6910 "movex x: adjust x component of light location\n"
6911 "movey y: adjust y component of light location\n"
6912 "movez z: adjust z component of light location\n"
6913 "angles x y z : set light angles\n"
6914 "anglesx x: set x component of light angles\n"
6915 "anglesy y: set y component of light angles\n"
6916 "anglesz z: set z component of light angles\n"
6917 "color r g b : set color of light (can be brighter than 1 1 1)\n"
6918 "radius radius : set radius (size) of light\n"
6919 "colorscale grey : multiply color of light (1 does nothing)\n"
6920 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
6921 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
6922 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
6923 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
6924 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
6925 "cubemap basename : set filter cubemap of light\n"
6926 "shadows 1/0 : turn on/off shadows\n"
6927 "corona n : set corona intensity\n"
6928 "coronasize n : set corona size (0-1)\n"
6929 "ambient n : set ambient intensity (0-1)\n"
6930 "diffuse n : set diffuse intensity (0-1)\n"
6931 "specular n : set specular intensity (0-1)\n"
6932 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6933 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6934 "<nothing> : print light properties to console\n"
6938 static void R_Shadow_EditLights_CopyInfo_f(void)
6940 if (!r_editlights.integer)
6942 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
6945 if (!r_shadow_selectedlight)
6947 Con_Print("No selected light.\n");
6950 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6951 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6952 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6953 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6954 if (r_shadow_selectedlight->cubemapname)
6955 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6957 r_shadow_bufferlight.cubemapname[0] = 0;
6958 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6959 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6960 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6961 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6962 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6963 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6964 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6967 static void R_Shadow_EditLights_PasteInfo_f(void)
6969 if (!r_editlights.integer)
6971 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6974 if (!r_shadow_selectedlight)
6976 Con_Print("No selected light.\n");
6979 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);
6982 static void R_Shadow_EditLights_Lock_f(void)
6984 if (!r_editlights.integer)
6986 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6989 if (r_editlights_lockcursor)
6991 r_editlights_lockcursor = false;
6994 if (!r_shadow_selectedlight)
6996 Con_Print("No selected light to lock on.\n");
6999 r_editlights_lockcursor = true;
7002 static void R_Shadow_EditLights_Init(void)
7004 Cvar_RegisterVariable(&r_editlights);
7005 Cvar_RegisterVariable(&r_editlights_cursordistance);
7006 Cvar_RegisterVariable(&r_editlights_cursorpushback);
7007 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
7008 Cvar_RegisterVariable(&r_editlights_cursorgrid);
7009 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
7010 Cvar_RegisterVariable(&r_editlights_drawproperties);
7011 Cvar_RegisterVariable(&r_editlights_current_origin);
7012 Cvar_RegisterVariable(&r_editlights_current_angles);
7013 Cvar_RegisterVariable(&r_editlights_current_color);
7014 Cvar_RegisterVariable(&r_editlights_current_radius);
7015 Cvar_RegisterVariable(&r_editlights_current_corona);
7016 Cvar_RegisterVariable(&r_editlights_current_coronasize);
7017 Cvar_RegisterVariable(&r_editlights_current_style);
7018 Cvar_RegisterVariable(&r_editlights_current_shadows);
7019 Cvar_RegisterVariable(&r_editlights_current_cubemap);
7020 Cvar_RegisterVariable(&r_editlights_current_ambient);
7021 Cvar_RegisterVariable(&r_editlights_current_diffuse);
7022 Cvar_RegisterVariable(&r_editlights_current_specular);
7023 Cvar_RegisterVariable(&r_editlights_current_normalmode);
7024 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
7025 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
7026 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
7027 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)");
7028 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
7029 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
7030 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
7031 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)");
7032 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
7033 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
7034 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
7035 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
7036 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
7037 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
7038 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)");
7039 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
7045 =============================================================================
7049 =============================================================================
7052 void R_CompleteLightPoint(float *ambient, float *diffuse, float *lightdir, const vec3_t p, const int flags, float lightmapintensity, float ambientintensity)
7054 int i, numlights, flag, q;
7057 float relativepoint[3];
7062 float sa[3], sx[3], sy[3], sz[3], sd[3];
7065 // use first order spherical harmonics to combine directional lights
7066 for (q = 0; q < 3; q++)
7067 sa[q] = sx[q] = sy[q] = sz[q] = sd[q] = 0;
7069 if (flags & LP_LIGHTMAP)
7071 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7073 float tempambient[3];
7074 for (q = 0; q < 3; q++)
7075 tempambient[q] = color[q] = relativepoint[q] = 0;
7076 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
7077 // calculate a weighted average light direction as well
7078 intensity = VectorLength(color);
7079 for (q = 0; q < 3; q++)
7081 sa[q] += (0.5f * color[q] + tempambient[q]) * lightmapintensity;
7082 sx[q] += (relativepoint[0] * color[q]) * lightmapintensity;
7083 sy[q] += (relativepoint[1] * color[q]) * lightmapintensity;
7084 sz[q] += (relativepoint[2] * color[q]) * lightmapintensity;
7085 sd[q] += (intensity * relativepoint[q]) * lightmapintensity;
7090 // unlit map - fullbright but scaled by lightmapintensity
7091 for (q = 0; q < 3; q++)
7092 sa[q] += lightmapintensity;
7096 if (flags & LP_RTWORLD)
7098 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7099 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7100 for (i = 0; i < numlights; i++)
7102 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7105 light = &dlight->rtlight;
7106 if (!(light->flags & flag))
7109 lightradius2 = light->radius * light->radius;
7110 VectorSubtract(light->shadoworigin, p, relativepoint);
7111 dist2 = VectorLength2(relativepoint);
7112 if (dist2 >= lightradius2)
7114 dist = sqrt(dist2) / light->radius;
7115 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
7116 if (intensity <= 0.0f)
7118 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)
7120 for (q = 0; q < 3; q++)
7121 color[q] = light->currentcolor[q] * intensity;
7122 intensity = VectorLength(color);
7123 VectorNormalize(relativepoint);
7124 for (q = 0; q < 3; q++)
7126 sa[q] += 0.5f * color[q];
7127 sx[q] += relativepoint[0] * color[q];
7128 sy[q] += relativepoint[1] * color[q];
7129 sz[q] += relativepoint[2] * color[q];
7130 sd[q] += intensity * relativepoint[q];
7133 // FIXME: sample bouncegrid too!
7136 if (flags & LP_DYNLIGHT)
7139 for (i = 0;i < r_refdef.scene.numlights;i++)
7141 light = r_refdef.scene.lights[i];
7143 lightradius2 = light->radius * light->radius;
7144 VectorSubtract(light->shadoworigin, p, relativepoint);
7145 dist2 = VectorLength2(relativepoint);
7146 if (dist2 >= lightradius2)
7148 dist = sqrt(dist2) / light->radius;
7149 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
7150 if (intensity <= 0.0f)
7152 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)
7154 for (q = 0; q < 3; q++)
7155 color[q] = light->currentcolor[q] * intensity;
7156 intensity = VectorLength(color);
7157 VectorNormalize(relativepoint);
7158 for (q = 0; q < 3; q++)
7160 sa[q] += 0.5f * color[q];
7161 sx[q] += relativepoint[0] * color[q];
7162 sy[q] += relativepoint[1] * color[q];
7163 sz[q] += relativepoint[2] * color[q];
7164 sd[q] += intensity * relativepoint[q];
7169 // calculate the weighted-average light direction (bentnormal)
7170 for (q = 0; q < 3; q++)
7171 lightdir[q] = sd[q];
7172 VectorNormalize(lightdir);
7173 for (q = 0; q < 3; q++)
7175 // extract the diffuse color along the chosen direction and scale it
7176 diffuse[q] = (lightdir[0] * sx[q] + lightdir[1] * sy[q] + lightdir[2] * sz[q]);
7177 // subtract some of diffuse from ambient
7178 ambient[q] = sa[q] + -0.333f * diffuse[q] + ambientintensity;