3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however. Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light. This technique is used heavily in many games (Doom3 does not support
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
142 #include "dpsoftrast.h"
146 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
149 static void R_Shadow_EditLights_Init(void);
151 typedef enum r_shadow_rendermode_e
153 R_SHADOW_RENDERMODE_NONE,
154 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
155 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
156 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
157 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
158 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
159 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
160 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
161 R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN,
162 R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN,
163 R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN,
164 R_SHADOW_RENDERMODE_LIGHT_GLSL,
165 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
166 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
167 R_SHADOW_RENDERMODE_SHADOWMAP2D
169 r_shadow_rendermode_t;
171 typedef enum r_shadow_shadowmode_e
173 R_SHADOW_SHADOWMODE_STENCIL,
174 R_SHADOW_SHADOWMODE_SHADOWMAP2D
176 r_shadow_shadowmode_t;
178 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
180 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
181 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
182 int r_shadow_scenemaxlights;
183 int r_shadow_scenenumlights;
184 rtlight_t **r_shadow_scenelightlist; // includes both static lights and dlights, as filtered by appropriate flags
185 qboolean r_shadow_usingshadowmap2d;
186 qboolean r_shadow_usingshadowmaportho;
187 int r_shadow_shadowmapside;
188 float r_shadow_lightshadowmap_texturescale[4]; // xy = scale, zw = offset
189 float r_shadow_lightshadowmap_parameters[4]; // x = frustum width in pixels (excludes border), y = z scale, z = size of viewport, w = z center
190 float r_shadow_modelshadowmap_texturescale[4]; // xy = scale, zw = offset
191 float r_shadow_modelshadowmap_parameters[4]; // xyz = scale, w = shadow brightness
193 int r_shadow_drawbuffer;
194 int r_shadow_readbuffer;
196 int r_shadow_cullface_front, r_shadow_cullface_back;
197 GLuint r_shadow_fbo2d;
198 r_shadow_shadowmode_t r_shadow_shadowmode;
199 int r_shadow_shadowmapfilterquality;
200 int r_shadow_shadowmapdepthbits;
201 int r_shadow_shadowmapmaxsize;
202 int r_shadow_shadowmaptexturesize;
203 qboolean r_shadow_shadowmapvsdct;
204 qboolean r_shadow_shadowmapsampler;
205 qboolean r_shadow_shadowmapshadowsampler;
206 int r_shadow_shadowmappcf;
207 int r_shadow_shadowmapborder;
208 matrix4x4_t r_shadow_shadowmapmatrix;
209 int r_shadow_lightscissor[4];
210 qboolean r_shadow_usingdeferredprepass;
211 qboolean r_shadow_shadowmapdepthtexture;
212 mod_alloclightmap_state_t r_shadow_shadowmapatlas_state;
213 int r_shadow_shadowmapatlas_modelshadows_x;
214 int r_shadow_shadowmapatlas_modelshadows_y;
215 int r_shadow_shadowmapatlas_modelshadows_size;
216 int maxshadowtriangles;
219 int maxshadowvertices;
220 float *shadowvertex3f;
230 unsigned char *shadowsides;
231 int *shadowsideslist;
238 int r_shadow_buffer_numleafpvsbytes;
239 unsigned char *r_shadow_buffer_visitingleafpvs;
240 unsigned char *r_shadow_buffer_leafpvs;
241 int *r_shadow_buffer_leaflist;
243 int r_shadow_buffer_numsurfacepvsbytes;
244 unsigned char *r_shadow_buffer_surfacepvs;
245 int *r_shadow_buffer_surfacelist;
246 unsigned char *r_shadow_buffer_surfacesides;
248 int r_shadow_buffer_numshadowtrispvsbytes;
249 unsigned char *r_shadow_buffer_shadowtrispvs;
250 int r_shadow_buffer_numlighttrispvsbytes;
251 unsigned char *r_shadow_buffer_lighttrispvs;
253 rtexturepool_t *r_shadow_texturepool;
254 rtexture_t *r_shadow_attenuationgradienttexture;
255 rtexture_t *r_shadow_attenuation2dtexture;
256 rtexture_t *r_shadow_attenuation3dtexture;
257 skinframe_t *r_shadow_lightcorona;
258 rtexture_t *r_shadow_shadowmap2ddepthbuffer;
259 rtexture_t *r_shadow_shadowmap2ddepthtexture;
260 rtexture_t *r_shadow_shadowmapvsdcttexture;
262 GLuint r_shadow_prepassgeometryfbo;
263 GLuint r_shadow_prepasslightingdiffusespecularfbo;
264 GLuint r_shadow_prepasslightingdiffusefbo;
265 int r_shadow_prepass_width;
266 int r_shadow_prepass_height;
267 rtexture_t *r_shadow_prepassgeometrydepthbuffer;
268 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
269 rtexture_t *r_shadow_prepasslightingdiffusetexture;
270 rtexture_t *r_shadow_prepasslightingspeculartexture;
272 // keep track of the provided framebuffer info
273 static int r_shadow_fb_fbo;
274 static rtexture_t *r_shadow_fb_depthtexture;
275 static rtexture_t *r_shadow_fb_colortexture;
277 // lights are reloaded when this changes
278 char r_shadow_mapname[MAX_QPATH];
280 // buffer for doing corona fading
281 unsigned int r_shadow_occlusion_buf = 0;
283 // used only for light filters (cubemaps)
284 rtexturepool_t *r_shadow_filters_texturepool;
286 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
287 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
288 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
289 cvar_t r_shadow_deferred = {CVAR_SAVE, "r_shadow_deferred", "0", "uses image-based lighting instead of geometry-based lighting, the method used renders a depth image and a normalmap image, renders lights into separate diffuse and specular images, and then combines this into the normal rendering, requires r_shadow_shadowmapping"};
290 cvar_t r_shadow_usebihculling = {0, "r_shadow_usebihculling", "1", "use BIH (Bounding Interval Hierarchy) for culling lit surfaces instead of BSP (Binary Space Partitioning)"};
291 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
292 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
293 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
294 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
295 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
296 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
297 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
298 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
299 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
300 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
301 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
302 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
303 cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
304 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
305 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
306 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
307 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
308 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
309 cvar_t r_shadow_realtime_world_importlightentitiesfrommap = {0, "r_shadow_realtime_world_importlightentitiesfrommap", "1", "load lights from .ent file or map entities at startup if no .rtlights or .lights file is present (if set to 2, always use the .ent or map entities)"};
310 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
311 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
312 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
313 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
314 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation (slower than compileportalculling but more exact)"};
315 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
316 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
317 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "1", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"};
318 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
319 cvar_t r_shadow_shadowmapping_useshadowsampler = {CVAR_SAVE, "r_shadow_shadowmapping_useshadowsampler", "1", "whether to use sampler2DShadow if available"};
320 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
321 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
322 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "limit of shadowmap side size - must be at least r_shadow_shadowmapping_bordersize+2"};
323 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "limit of shadowmap side size - can not be more than 1/8th of atlassize because lights store 6 sides (2x3 grid) and sometimes 12 sides (4x3 grid for shadows from EF_NOSELFSHADOW entities) and there are multiple lights..."};
324 cvar_t r_shadow_shadowmapping_texturesize = { CVAR_SAVE, "r_shadow_shadowmapping_texturesize", "4096", "size of shadowmap atlas texture - all shadowmaps are packed into this texture at frame start"};
325 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
326 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
327 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
328 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
329 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
330 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
331 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
332 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
333 cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
334 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
335 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
336 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect OpenGL 2.0 render path)"};
337 cvar_t r_shadow_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)"};
338 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"};
339 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"};
340 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" };
341 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)"};
342 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"};
343 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"};
344 cvar_t r_shadow_bouncegrid_dynamic_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
345 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)"};
346 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)"};
347 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"};
348 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)"};
349 cvar_t r_shadow_bouncegrid_dynamic_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_spacing", "64", "unit size of bouncegrid pixel"};
350 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"};
351 cvar_t r_shadow_bouncegrid_dynamic_x = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_x", "64", "maximum texture size of bouncegrid on X axis"};
352 cvar_t r_shadow_bouncegrid_dynamic_y = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_y", "64", "maximum texture size of bouncegrid on Y axis"};
353 cvar_t r_shadow_bouncegrid_dynamic_z = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_z", "32", "maximum texture size of bouncegrid on Z axis"};
354 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"};
355 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)"};
356 cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
357 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"};
358 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"};
359 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)" };
360 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"};
361 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "0.25", "brightness of particles contributing to bouncegrid texture"};
362 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" };
363 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)" };
364 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"};
365 cvar_t r_shadow_bouncegrid_static = {CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
366 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" };
367 cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
368 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"};
369 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"};
370 cvar_t r_shadow_bouncegrid_static_maxphotons = {CVAR_SAVE, "r_shadow_bouncegrid_static_maxphotons", "250000", "upper bound on photons in static mode"};
371 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)" };
372 cvar_t r_shadow_bouncegrid_static_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_static_spacing", "64", "unit size of bouncegrid pixel when in static mode"};
373 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
374 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"};
375 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!"};
376 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
377 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
378 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
379 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
380 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
381 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
382 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
383 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
384 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
385 cvar_t r_editlights_drawproperties = {0, "r_editlights_drawproperties", "1", "draw properties of currently selected light"};
386 cvar_t r_editlights_current_origin = {0, "r_editlights_current_origin", "0 0 0", "origin of selected light"};
387 cvar_t r_editlights_current_angles = {0, "r_editlights_current_angles", "0 0 0", "angles of selected light"};
388 cvar_t r_editlights_current_color = {0, "r_editlights_current_color", "1 1 1", "color of selected light"};
389 cvar_t r_editlights_current_radius = {0, "r_editlights_current_radius", "0", "radius of selected light"};
390 cvar_t r_editlights_current_corona = {0, "r_editlights_current_corona", "0", "corona intensity of selected light"};
391 cvar_t r_editlights_current_coronasize = {0, "r_editlights_current_coronasize", "0", "corona size of selected light"};
392 cvar_t r_editlights_current_style = {0, "r_editlights_current_style", "0", "style of selected light"};
393 cvar_t r_editlights_current_shadows = {0, "r_editlights_current_shadows", "0", "shadows flag of selected light"};
394 cvar_t r_editlights_current_cubemap = {0, "r_editlights_current_cubemap", "0", "cubemap of selected light"};
395 cvar_t r_editlights_current_ambient = {0, "r_editlights_current_ambient", "0", "ambient intensity of selected light"};
396 cvar_t r_editlights_current_diffuse = {0, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"};
397 cvar_t r_editlights_current_specular = {0, "r_editlights_current_specular", "1", "specular intensity of selected light"};
398 cvar_t r_editlights_current_normalmode = {0, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"};
399 cvar_t r_editlights_current_realtimemode = {0, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"};
401 r_shadow_bouncegrid_state_t r_shadow_bouncegrid_state;
403 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
404 #define ATTENTABLESIZE 256
405 // 1D gradient, 2D circle and 3D sphere attenuation textures
406 #define ATTEN1DSIZE 32
407 #define ATTEN2DSIZE 64
408 #define ATTEN3DSIZE 32
410 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
411 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
412 static float r_shadow_attentable[ATTENTABLESIZE+1];
414 rtlight_t *r_shadow_compilingrtlight;
415 static memexpandablearray_t r_shadow_worldlightsarray;
416 dlight_t *r_shadow_selectedlight;
417 dlight_t r_shadow_bufferlight;
418 vec3_t r_editlights_cursorlocation;
419 qboolean r_editlights_lockcursor;
421 extern int con_vislines;
423 void R_Shadow_UncompileWorldLights(void);
424 void R_Shadow_ClearWorldLights(void);
425 void R_Shadow_SaveWorldLights(void);
426 void R_Shadow_LoadWorldLights(void);
427 void R_Shadow_LoadLightsFile(void);
428 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
429 void R_Shadow_EditLights_Reload_f(void);
430 void R_Shadow_ValidateCvars(void);
431 static void R_Shadow_MakeTextures(void);
433 #define EDLIGHTSPRSIZE 8
434 skinframe_t *r_editlights_sprcursor;
435 skinframe_t *r_editlights_sprlight;
436 skinframe_t *r_editlights_sprnoshadowlight;
437 skinframe_t *r_editlights_sprcubemaplight;
438 skinframe_t *r_editlights_sprcubemapnoshadowlight;
439 skinframe_t *r_editlights_sprselection;
441 static void R_Shadow_DrawModelShadowMaps(void);
442 static void R_Shadow_MakeShadowMap(int texturesize);
443 static void R_Shadow_MakeVSDCT(void);
444 static void R_Shadow_SetShadowMode(void)
446 r_shadow_shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
447 r_shadow_shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
448 r_shadow_shadowmapmaxsize = bound(r_shadow_shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, r_shadow_shadowmaptexturesize / 8);
449 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
450 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
451 r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
452 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
453 r_shadow_shadowmapsampler = false;
454 r_shadow_shadowmappcf = 0;
455 r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
456 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
457 Mod_AllocLightmap_Init(&r_shadow_shadowmapatlas_state, r_main_mempool, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize);
458 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
460 switch(vid.renderpath)
462 case RENDERPATH_GL20:
463 if(r_shadow_shadowmapfilterquality < 0)
465 if (!r_fb.usedepthtextures)
466 r_shadow_shadowmappcf = 1;
467 else if((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && vid.support.arb_shadow && r_shadow_shadowmapshadowsampler)
469 r_shadow_shadowmapsampler = true;
470 r_shadow_shadowmappcf = 1;
472 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
473 r_shadow_shadowmappcf = 1;
474 else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa"))
475 r_shadow_shadowmappcf = 1;
477 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
481 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
482 switch (r_shadow_shadowmapfilterquality)
487 r_shadow_shadowmappcf = 1;
490 r_shadow_shadowmappcf = 1;
493 r_shadow_shadowmappcf = 2;
497 if (!r_fb.usedepthtextures)
498 r_shadow_shadowmapsampler = false;
499 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
501 case RENDERPATH_D3D9:
502 case RENDERPATH_D3D10:
503 case RENDERPATH_D3D11:
504 case RENDERPATH_SOFT:
505 r_shadow_shadowmapsampler = false;
506 r_shadow_shadowmappcf = 1;
507 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
509 case RENDERPATH_GL11:
510 case RENDERPATH_GL13:
511 case RENDERPATH_GLES1:
512 case RENDERPATH_GLES2:
517 if(R_CompileShader_CheckStaticParms())
521 qboolean R_Shadow_ShadowMappingEnabled(void)
523 switch (r_shadow_shadowmode)
525 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
532 static void R_Shadow_FreeShadowMaps(void)
534 Mod_AllocLightmap_Free(&r_shadow_shadowmapatlas_state);
536 R_Shadow_SetShadowMode();
538 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
542 if (r_shadow_shadowmap2ddepthtexture)
543 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
544 r_shadow_shadowmap2ddepthtexture = NULL;
546 if (r_shadow_shadowmap2ddepthbuffer)
547 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
548 r_shadow_shadowmap2ddepthbuffer = NULL;
550 if (r_shadow_shadowmapvsdcttexture)
551 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
552 r_shadow_shadowmapvsdcttexture = NULL;
555 static void r_shadow_start(void)
557 // allocate vertex processing arrays
558 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
559 r_shadow_attenuationgradienttexture = NULL;
560 r_shadow_attenuation2dtexture = NULL;
561 r_shadow_attenuation3dtexture = NULL;
562 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
563 r_shadow_shadowmap2ddepthtexture = NULL;
564 r_shadow_shadowmap2ddepthbuffer = NULL;
565 r_shadow_shadowmapvsdcttexture = NULL;
566 r_shadow_shadowmapmaxsize = 0;
567 r_shadow_shadowmaptexturesize = 0;
568 r_shadow_shadowmapfilterquality = -1;
569 r_shadow_shadowmapdepthbits = 0;
570 r_shadow_shadowmapvsdct = false;
571 r_shadow_shadowmapsampler = false;
572 r_shadow_shadowmappcf = 0;
575 R_Shadow_FreeShadowMaps();
577 r_shadow_texturepool = NULL;
578 r_shadow_filters_texturepool = NULL;
579 R_Shadow_ValidateCvars();
580 R_Shadow_MakeTextures();
581 r_shadow_scenemaxlights = 0;
582 r_shadow_scenenumlights = 0;
583 r_shadow_scenelightlist = NULL;
584 maxshadowtriangles = 0;
585 shadowelements = NULL;
586 maxshadowvertices = 0;
587 shadowvertex3f = NULL;
595 shadowmarklist = NULL;
600 shadowsideslist = NULL;
601 r_shadow_buffer_numleafpvsbytes = 0;
602 r_shadow_buffer_visitingleafpvs = NULL;
603 r_shadow_buffer_leafpvs = NULL;
604 r_shadow_buffer_leaflist = NULL;
605 r_shadow_buffer_numsurfacepvsbytes = 0;
606 r_shadow_buffer_surfacepvs = NULL;
607 r_shadow_buffer_surfacelist = NULL;
608 r_shadow_buffer_surfacesides = NULL;
609 r_shadow_buffer_numshadowtrispvsbytes = 0;
610 r_shadow_buffer_shadowtrispvs = NULL;
611 r_shadow_buffer_numlighttrispvsbytes = 0;
612 r_shadow_buffer_lighttrispvs = NULL;
614 r_shadow_usingdeferredprepass = false;
615 r_shadow_prepass_width = r_shadow_prepass_height = 0;
617 // determine renderpath specific capabilities, we don't need to figure
618 // these out per frame...
619 switch(vid.renderpath)
621 case RENDERPATH_GL20:
622 r_shadow_bouncegrid_state.allowdirectionalshading = true;
623 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
625 case RENDERPATH_GLES2:
626 // for performance reasons, do not use directional shading on GLES devices
627 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
629 // these renderpaths do not currently have the code to display the bouncegrid, so disable it on them...
630 case RENDERPATH_GL11:
631 case RENDERPATH_GL13:
632 case RENDERPATH_GLES1:
633 case RENDERPATH_SOFT:
634 case RENDERPATH_D3D9:
635 case RENDERPATH_D3D10:
636 case RENDERPATH_D3D11:
641 static void R_Shadow_FreeDeferred(void);
642 static void r_shadow_shutdown(void)
645 R_Shadow_UncompileWorldLights();
647 R_Shadow_FreeShadowMaps();
649 r_shadow_usingdeferredprepass = false;
650 if (r_shadow_prepass_width)
651 R_Shadow_FreeDeferred();
652 r_shadow_prepass_width = r_shadow_prepass_height = 0;
655 r_shadow_scenemaxlights = 0;
656 r_shadow_scenenumlights = 0;
657 if (r_shadow_scenelightlist)
658 Mem_Free(r_shadow_scenelightlist);
659 r_shadow_scenelightlist = NULL;
660 r_shadow_bouncegrid_state.highpixels = NULL;
661 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
662 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
663 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
664 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
665 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
666 r_shadow_bouncegrid_state.maxsplatpaths = 0;
667 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
668 r_shadow_attenuationgradienttexture = NULL;
669 r_shadow_attenuation2dtexture = NULL;
670 r_shadow_attenuation3dtexture = NULL;
671 R_FreeTexturePool(&r_shadow_texturepool);
672 R_FreeTexturePool(&r_shadow_filters_texturepool);
673 maxshadowtriangles = 0;
675 Mem_Free(shadowelements);
676 shadowelements = NULL;
678 Mem_Free(shadowvertex3f);
679 shadowvertex3f = NULL;
682 Mem_Free(vertexupdate);
685 Mem_Free(vertexremap);
691 Mem_Free(shadowmark);
694 Mem_Free(shadowmarklist);
695 shadowmarklist = NULL;
700 Mem_Free(shadowsides);
703 Mem_Free(shadowsideslist);
704 shadowsideslist = NULL;
705 r_shadow_buffer_numleafpvsbytes = 0;
706 if (r_shadow_buffer_visitingleafpvs)
707 Mem_Free(r_shadow_buffer_visitingleafpvs);
708 r_shadow_buffer_visitingleafpvs = NULL;
709 if (r_shadow_buffer_leafpvs)
710 Mem_Free(r_shadow_buffer_leafpvs);
711 r_shadow_buffer_leafpvs = NULL;
712 if (r_shadow_buffer_leaflist)
713 Mem_Free(r_shadow_buffer_leaflist);
714 r_shadow_buffer_leaflist = NULL;
715 r_shadow_buffer_numsurfacepvsbytes = 0;
716 if (r_shadow_buffer_surfacepvs)
717 Mem_Free(r_shadow_buffer_surfacepvs);
718 r_shadow_buffer_surfacepvs = NULL;
719 if (r_shadow_buffer_surfacelist)
720 Mem_Free(r_shadow_buffer_surfacelist);
721 r_shadow_buffer_surfacelist = NULL;
722 if (r_shadow_buffer_surfacesides)
723 Mem_Free(r_shadow_buffer_surfacesides);
724 r_shadow_buffer_surfacesides = NULL;
725 r_shadow_buffer_numshadowtrispvsbytes = 0;
726 if (r_shadow_buffer_shadowtrispvs)
727 Mem_Free(r_shadow_buffer_shadowtrispvs);
728 r_shadow_buffer_numlighttrispvsbytes = 0;
729 if (r_shadow_buffer_lighttrispvs)
730 Mem_Free(r_shadow_buffer_lighttrispvs);
733 static void r_shadow_newmap(void)
735 r_shadow_bouncegrid_state.highpixels = NULL;
736 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
737 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
738 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
739 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
740 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
741 r_shadow_bouncegrid_state.maxsplatpaths = 0;
742 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
743 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
744 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
745 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
746 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
747 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
748 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
749 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
750 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
751 R_Shadow_EditLights_Reload_f();
754 void R_Shadow_Init(void)
756 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
757 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
758 Cvar_RegisterVariable(&r_shadow_usebihculling);
759 Cvar_RegisterVariable(&r_shadow_usenormalmap);
760 Cvar_RegisterVariable(&r_shadow_debuglight);
761 Cvar_RegisterVariable(&r_shadow_deferred);
762 Cvar_RegisterVariable(&r_shadow_gloss);
763 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
764 Cvar_RegisterVariable(&r_shadow_glossintensity);
765 Cvar_RegisterVariable(&r_shadow_glossexponent);
766 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
767 Cvar_RegisterVariable(&r_shadow_glossexact);
768 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
769 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
770 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
771 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
772 Cvar_RegisterVariable(&r_shadow_projectdistance);
773 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
774 Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
775 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
776 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
777 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
778 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
779 Cvar_RegisterVariable(&r_shadow_realtime_world);
780 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
781 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
782 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
783 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
784 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
785 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
786 Cvar_RegisterVariable(&r_shadow_scissor);
787 Cvar_RegisterVariable(&r_shadow_shadowmapping);
788 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
789 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
790 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
791 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
792 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
793 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
794 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
795 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturesize);
796 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
797 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
798 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
799 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
800 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
801 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
802 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
803 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
804 Cvar_RegisterVariable(&r_shadow_polygonfactor);
805 Cvar_RegisterVariable(&r_shadow_polygonoffset);
806 Cvar_RegisterVariable(&r_shadow_texture3d);
807 Cvar_RegisterVariable(&r_shadow_bouncegrid);
808 Cvar_RegisterVariable(&r_shadow_bouncegrid_blur);
809 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
810 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_bounceminimumintensity);
811 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_culllightpaths);
812 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_directionalshading);
813 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_dlightparticlemultiplier);
814 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_hitmodels);
815 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_lightradiusscale);
816 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxbounce);
817 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxphotons);
818 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_quality);
819 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_spacing);
820 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_updateinterval);
821 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_x);
822 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_y);
823 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_z);
824 Cvar_RegisterVariable(&r_shadow_bouncegrid_floatcolors);
825 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
826 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
827 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize_conespread);
828 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize_initial);
829 Cvar_RegisterVariable(&r_shadow_bouncegrid_normalizevectors);
830 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
831 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
832 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_seed);
833 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_type);
834 Cvar_RegisterVariable(&r_shadow_bouncegrid_sortlightpaths);
835 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
836 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_bounceminimumintensity);
837 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
838 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
839 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
840 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxphotons);
841 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_quality);
842 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_spacing);
843 Cvar_RegisterVariable(&r_coronas);
844 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
845 Cvar_RegisterVariable(&r_coronas_occlusionquery);
846 Cvar_RegisterVariable(&gl_flashblend);
847 Cvar_RegisterVariable(&gl_ext_separatestencil);
848 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
849 R_Shadow_EditLights_Init();
850 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
851 r_shadow_scenemaxlights = 0;
852 r_shadow_scenenumlights = 0;
853 r_shadow_scenelightlist = NULL;
854 maxshadowtriangles = 0;
855 shadowelements = NULL;
856 maxshadowvertices = 0;
857 shadowvertex3f = NULL;
865 shadowmarklist = NULL;
870 shadowsideslist = NULL;
871 r_shadow_buffer_numleafpvsbytes = 0;
872 r_shadow_buffer_visitingleafpvs = NULL;
873 r_shadow_buffer_leafpvs = NULL;
874 r_shadow_buffer_leaflist = NULL;
875 r_shadow_buffer_numsurfacepvsbytes = 0;
876 r_shadow_buffer_surfacepvs = NULL;
877 r_shadow_buffer_surfacelist = NULL;
878 r_shadow_buffer_surfacesides = NULL;
879 r_shadow_buffer_shadowtrispvs = NULL;
880 r_shadow_buffer_lighttrispvs = NULL;
881 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
884 matrix4x4_t matrix_attenuationxyz =
887 {0.5, 0.0, 0.0, 0.5},
888 {0.0, 0.5, 0.0, 0.5},
889 {0.0, 0.0, 0.5, 0.5},
894 matrix4x4_t matrix_attenuationz =
897 {0.0, 0.0, 0.5, 0.5},
898 {0.0, 0.0, 0.0, 0.5},
899 {0.0, 0.0, 0.0, 0.5},
904 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
906 numvertices = ((numvertices + 255) & ~255) * vertscale;
907 numtriangles = ((numtriangles + 255) & ~255) * triscale;
908 // make sure shadowelements is big enough for this volume
909 if (maxshadowtriangles < numtriangles)
911 maxshadowtriangles = numtriangles;
913 Mem_Free(shadowelements);
914 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
916 // make sure shadowvertex3f is big enough for this volume
917 if (maxshadowvertices < numvertices)
919 maxshadowvertices = numvertices;
921 Mem_Free(shadowvertex3f);
922 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
926 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
928 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
929 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
930 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
931 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
932 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
934 if (r_shadow_buffer_visitingleafpvs)
935 Mem_Free(r_shadow_buffer_visitingleafpvs);
936 if (r_shadow_buffer_leafpvs)
937 Mem_Free(r_shadow_buffer_leafpvs);
938 if (r_shadow_buffer_leaflist)
939 Mem_Free(r_shadow_buffer_leaflist);
940 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
941 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
942 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
943 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
945 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
947 if (r_shadow_buffer_surfacepvs)
948 Mem_Free(r_shadow_buffer_surfacepvs);
949 if (r_shadow_buffer_surfacelist)
950 Mem_Free(r_shadow_buffer_surfacelist);
951 if (r_shadow_buffer_surfacesides)
952 Mem_Free(r_shadow_buffer_surfacesides);
953 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
954 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
955 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
956 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
958 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
960 if (r_shadow_buffer_shadowtrispvs)
961 Mem_Free(r_shadow_buffer_shadowtrispvs);
962 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
963 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
965 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
967 if (r_shadow_buffer_lighttrispvs)
968 Mem_Free(r_shadow_buffer_lighttrispvs);
969 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
970 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
974 void R_Shadow_PrepareShadowMark(int numtris)
976 // make sure shadowmark is big enough for this volume
977 if (maxshadowmark < numtris)
979 maxshadowmark = numtris;
981 Mem_Free(shadowmark);
983 Mem_Free(shadowmarklist);
984 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
985 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
989 // if shadowmarkcount wrapped we clear the array and adjust accordingly
990 if (shadowmarkcount == 0)
993 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
998 void R_Shadow_PrepareShadowSides(int numtris)
1000 if (maxshadowsides < numtris)
1002 maxshadowsides = numtris;
1004 Mem_Free(shadowsides);
1005 if (shadowsideslist)
1006 Mem_Free(shadowsideslist);
1007 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
1008 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
1013 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)
1016 int outtriangles = 0, outvertices = 0;
1018 const float *vertex;
1019 float ratio, direction[3], projectvector[3];
1021 if (projectdirection)
1022 VectorScale(projectdirection, projectdistance, projectvector);
1024 VectorClear(projectvector);
1026 // create the vertices
1027 if (projectdirection)
1029 for (i = 0;i < numshadowmarktris;i++)
1031 element = inelement3i + shadowmarktris[i] * 3;
1032 for (j = 0;j < 3;j++)
1034 if (vertexupdate[element[j]] != vertexupdatenum)
1036 vertexupdate[element[j]] = vertexupdatenum;
1037 vertexremap[element[j]] = outvertices;
1038 vertex = invertex3f + element[j] * 3;
1039 // project one copy of the vertex according to projectvector
1040 VectorCopy(vertex, outvertex3f);
1041 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1050 for (i = 0;i < numshadowmarktris;i++)
1052 element = inelement3i + shadowmarktris[i] * 3;
1053 for (j = 0;j < 3;j++)
1055 if (vertexupdate[element[j]] != vertexupdatenum)
1057 vertexupdate[element[j]] = vertexupdatenum;
1058 vertexremap[element[j]] = outvertices;
1059 vertex = invertex3f + element[j] * 3;
1060 // project one copy of the vertex to the sphere radius of the light
1061 // (FIXME: would projecting it to the light box be better?)
1062 VectorSubtract(vertex, projectorigin, direction);
1063 ratio = projectdistance / VectorLength(direction);
1064 VectorCopy(vertex, outvertex3f);
1065 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1073 if (r_shadow_frontsidecasting.integer)
1075 for (i = 0;i < numshadowmarktris;i++)
1077 int remappedelement[3];
1079 const int *neighbortriangle;
1081 markindex = shadowmarktris[i] * 3;
1082 element = inelement3i + markindex;
1083 neighbortriangle = inneighbor3i + markindex;
1084 // output the front and back triangles
1085 outelement3i[0] = vertexremap[element[0]];
1086 outelement3i[1] = vertexremap[element[1]];
1087 outelement3i[2] = vertexremap[element[2]];
1088 outelement3i[3] = vertexremap[element[2]] + 1;
1089 outelement3i[4] = vertexremap[element[1]] + 1;
1090 outelement3i[5] = vertexremap[element[0]] + 1;
1094 // output the sides (facing outward from this triangle)
1095 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1097 remappedelement[0] = vertexremap[element[0]];
1098 remappedelement[1] = vertexremap[element[1]];
1099 outelement3i[0] = remappedelement[1];
1100 outelement3i[1] = remappedelement[0];
1101 outelement3i[2] = remappedelement[0] + 1;
1102 outelement3i[3] = remappedelement[1];
1103 outelement3i[4] = remappedelement[0] + 1;
1104 outelement3i[5] = remappedelement[1] + 1;
1109 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1111 remappedelement[1] = vertexremap[element[1]];
1112 remappedelement[2] = vertexremap[element[2]];
1113 outelement3i[0] = remappedelement[2];
1114 outelement3i[1] = remappedelement[1];
1115 outelement3i[2] = remappedelement[1] + 1;
1116 outelement3i[3] = remappedelement[2];
1117 outelement3i[4] = remappedelement[1] + 1;
1118 outelement3i[5] = remappedelement[2] + 1;
1123 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1125 remappedelement[0] = vertexremap[element[0]];
1126 remappedelement[2] = vertexremap[element[2]];
1127 outelement3i[0] = remappedelement[0];
1128 outelement3i[1] = remappedelement[2];
1129 outelement3i[2] = remappedelement[2] + 1;
1130 outelement3i[3] = remappedelement[0];
1131 outelement3i[4] = remappedelement[2] + 1;
1132 outelement3i[5] = remappedelement[0] + 1;
1141 for (i = 0;i < numshadowmarktris;i++)
1143 int remappedelement[3];
1145 const int *neighbortriangle;
1147 markindex = shadowmarktris[i] * 3;
1148 element = inelement3i + markindex;
1149 neighbortriangle = inneighbor3i + markindex;
1150 // output the front and back triangles
1151 outelement3i[0] = vertexremap[element[2]];
1152 outelement3i[1] = vertexremap[element[1]];
1153 outelement3i[2] = vertexremap[element[0]];
1154 outelement3i[3] = vertexremap[element[0]] + 1;
1155 outelement3i[4] = vertexremap[element[1]] + 1;
1156 outelement3i[5] = vertexremap[element[2]] + 1;
1160 // output the sides (facing outward from this triangle)
1161 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1163 remappedelement[0] = vertexremap[element[0]];
1164 remappedelement[1] = vertexremap[element[1]];
1165 outelement3i[0] = remappedelement[0];
1166 outelement3i[1] = remappedelement[1];
1167 outelement3i[2] = remappedelement[1] + 1;
1168 outelement3i[3] = remappedelement[0];
1169 outelement3i[4] = remappedelement[1] + 1;
1170 outelement3i[5] = remappedelement[0] + 1;
1175 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1177 remappedelement[1] = vertexremap[element[1]];
1178 remappedelement[2] = vertexremap[element[2]];
1179 outelement3i[0] = remappedelement[1];
1180 outelement3i[1] = remappedelement[2];
1181 outelement3i[2] = remappedelement[2] + 1;
1182 outelement3i[3] = remappedelement[1];
1183 outelement3i[4] = remappedelement[2] + 1;
1184 outelement3i[5] = remappedelement[1] + 1;
1189 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1191 remappedelement[0] = vertexremap[element[0]];
1192 remappedelement[2] = vertexremap[element[2]];
1193 outelement3i[0] = remappedelement[2];
1194 outelement3i[1] = remappedelement[0];
1195 outelement3i[2] = remappedelement[0] + 1;
1196 outelement3i[3] = remappedelement[2];
1197 outelement3i[4] = remappedelement[0] + 1;
1198 outelement3i[5] = remappedelement[2] + 1;
1206 *outnumvertices = outvertices;
1207 return outtriangles;
1210 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)
1213 int outtriangles = 0, outvertices = 0;
1215 const float *vertex;
1216 float ratio, direction[3], projectvector[3];
1219 if (projectdirection)
1220 VectorScale(projectdirection, projectdistance, projectvector);
1222 VectorClear(projectvector);
1224 for (i = 0;i < numshadowmarktris;i++)
1226 int remappedelement[3];
1228 const int *neighbortriangle;
1230 markindex = shadowmarktris[i] * 3;
1231 neighbortriangle = inneighbor3i + markindex;
1232 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1233 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1234 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1235 if (side[0] + side[1] + side[2] == 0)
1239 element = inelement3i + markindex;
1241 // create the vertices
1242 for (j = 0;j < 3;j++)
1244 if (side[j] + side[j+1] == 0)
1247 if (vertexupdate[k] != vertexupdatenum)
1249 vertexupdate[k] = vertexupdatenum;
1250 vertexremap[k] = outvertices;
1251 vertex = invertex3f + k * 3;
1252 VectorCopy(vertex, outvertex3f);
1253 if (projectdirection)
1255 // project one copy of the vertex according to projectvector
1256 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1260 // project one copy of the vertex to the sphere radius of the light
1261 // (FIXME: would projecting it to the light box be better?)
1262 VectorSubtract(vertex, projectorigin, direction);
1263 ratio = projectdistance / VectorLength(direction);
1264 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1271 // output the sides (facing outward from this triangle)
1274 remappedelement[0] = vertexremap[element[0]];
1275 remappedelement[1] = vertexremap[element[1]];
1276 outelement3i[0] = remappedelement[1];
1277 outelement3i[1] = remappedelement[0];
1278 outelement3i[2] = remappedelement[0] + 1;
1279 outelement3i[3] = remappedelement[1];
1280 outelement3i[4] = remappedelement[0] + 1;
1281 outelement3i[5] = remappedelement[1] + 1;
1288 remappedelement[1] = vertexremap[element[1]];
1289 remappedelement[2] = vertexremap[element[2]];
1290 outelement3i[0] = remappedelement[2];
1291 outelement3i[1] = remappedelement[1];
1292 outelement3i[2] = remappedelement[1] + 1;
1293 outelement3i[3] = remappedelement[2];
1294 outelement3i[4] = remappedelement[1] + 1;
1295 outelement3i[5] = remappedelement[2] + 1;
1302 remappedelement[0] = vertexremap[element[0]];
1303 remappedelement[2] = vertexremap[element[2]];
1304 outelement3i[0] = remappedelement[0];
1305 outelement3i[1] = remappedelement[2];
1306 outelement3i[2] = remappedelement[2] + 1;
1307 outelement3i[3] = remappedelement[0];
1308 outelement3i[4] = remappedelement[2] + 1;
1309 outelement3i[5] = remappedelement[0] + 1;
1316 *outnumvertices = outvertices;
1317 return outtriangles;
1320 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)
1326 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1328 tend = firsttriangle + numtris;
1329 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1331 // surface box entirely inside light box, no box cull
1332 if (projectdirection)
1334 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1336 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1337 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1338 shadowmarklist[numshadowmark++] = t;
1343 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1344 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1345 shadowmarklist[numshadowmark++] = t;
1350 // surface box not entirely inside light box, cull each triangle
1351 if (projectdirection)
1353 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1355 v[0] = invertex3f + e[0] * 3;
1356 v[1] = invertex3f + e[1] * 3;
1357 v[2] = invertex3f + e[2] * 3;
1358 TriangleNormal(v[0], v[1], v[2], normal);
1359 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1360 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1361 shadowmarklist[numshadowmark++] = t;
1366 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1368 v[0] = invertex3f + e[0] * 3;
1369 v[1] = invertex3f + e[1] * 3;
1370 v[2] = invertex3f + e[2] * 3;
1371 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1372 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1373 shadowmarklist[numshadowmark++] = t;
1379 static qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1384 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1386 // check if the shadow volume intersects the near plane
1388 // a ray between the eye and light origin may intersect the caster,
1389 // indicating that the shadow may touch the eye location, however we must
1390 // test the near plane (a polygon), not merely the eye location, so it is
1391 // easiest to enlarge the caster bounding shape slightly for this.
1397 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)
1399 int i, tris, outverts;
1400 if (projectdistance < 0.1)
1402 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1405 if (!numverts || !nummarktris)
1407 // make sure shadowelements is big enough for this volume
1408 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1409 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1411 if (maxvertexupdate < numverts)
1413 maxvertexupdate = numverts;
1415 Mem_Free(vertexupdate);
1417 Mem_Free(vertexremap);
1418 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1419 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1420 vertexupdatenum = 0;
1423 if (vertexupdatenum == 0)
1425 vertexupdatenum = 1;
1426 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1427 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1430 for (i = 0;i < nummarktris;i++)
1431 shadowmark[marktris[i]] = shadowmarkcount;
1433 if (r_shadow_compilingrtlight)
1435 // if we're compiling an rtlight, capture the mesh
1436 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1437 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1438 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1439 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1441 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1443 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1444 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1445 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1449 // decide which type of shadow to generate and set stencil mode
1450 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1451 // generate the sides or a solid volume, depending on type
1452 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1453 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1455 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1456 r_refdef.stats[r_stat_lights_dynamicshadowtriangles] += tris;
1457 r_refdef.stats[r_stat_lights_shadowtriangles] += tris;
1458 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1460 // increment stencil if frontface is infront of depthbuffer
1461 GL_CullFace(r_refdef.view.cullface_front);
1462 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1463 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1464 // decrement stencil if backface is infront of depthbuffer
1465 GL_CullFace(r_refdef.view.cullface_back);
1466 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1468 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1470 // decrement stencil if backface is behind depthbuffer
1471 GL_CullFace(r_refdef.view.cullface_front);
1472 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1473 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1474 // increment stencil if frontface is behind depthbuffer
1475 GL_CullFace(r_refdef.view.cullface_back);
1476 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1478 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1479 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1483 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1485 // p1, p2, p3 are in the cubemap's local coordinate system
1486 // bias = border/(size - border)
1489 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1490 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1491 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1492 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1494 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1495 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1496 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1497 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1499 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1500 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1501 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1503 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1504 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1505 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1506 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1508 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1509 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1510 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1511 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1513 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1514 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1515 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1517 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1518 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1519 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1520 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1522 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1523 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1524 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1525 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1527 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1528 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1529 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1534 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1536 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1537 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1540 VectorSubtract(maxs, mins, radius);
1541 VectorScale(radius, 0.5f, radius);
1542 VectorAdd(mins, radius, center);
1543 Matrix4x4_Transform(worldtolight, center, lightcenter);
1544 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1545 VectorSubtract(lightcenter, lightradius, pmin);
1546 VectorAdd(lightcenter, lightradius, pmax);
1548 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1549 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1550 if(ap1 > bias*an1 && ap2 > bias*an2)
1552 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1553 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1554 if(an1 > bias*ap1 && an2 > bias*ap2)
1556 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1557 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1559 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1560 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1561 if(ap1 > bias*an1 && ap2 > bias*an2)
1563 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1564 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1565 if(an1 > bias*ap1 && an2 > bias*ap2)
1567 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1568 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1570 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1571 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1572 if(ap1 > bias*an1 && ap2 > bias*an2)
1574 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1575 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1576 if(an1 > bias*ap1 && an2 > bias*ap2)
1578 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1579 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1584 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1586 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1588 // p is in the cubemap's local coordinate system
1589 // bias = border/(size - border)
1590 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1591 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1592 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1594 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1595 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1596 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1597 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1598 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1599 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1603 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1607 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1608 float scale = (size - 2*border)/size, len;
1609 float bias = border / (float)(size - border), dp, dn, ap, an;
1610 // check if cone enclosing side would cross frustum plane
1611 scale = 2 / (scale*scale + 2);
1612 Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
1613 for (i = 0;i < 5;i++)
1615 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
1617 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1618 len = scale*VectorLength2(n);
1619 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1620 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1621 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1623 if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1625 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1626 len = scale*VectorLength2(n);
1627 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1628 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1629 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1631 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1632 // check if frustum corners/origin cross plane sides
1634 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1635 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1636 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1637 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1638 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1639 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1640 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1641 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1642 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1643 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1644 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1645 for (i = 0;i < 4;i++)
1647 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1648 VectorSubtract(n, p, n);
1649 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1650 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1651 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1652 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1653 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1654 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1655 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1656 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1657 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1660 // finite version, assumes corners are a finite distance from origin dependent on far plane
1661 for (i = 0;i < 5;i++)
1663 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1664 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1665 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1666 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1667 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1668 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1669 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1670 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1671 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1672 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1675 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1678 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)
1686 int mask, surfacemask = 0;
1687 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1689 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1690 tend = firsttriangle + numtris;
1691 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1693 // surface box entirely inside light box, no box cull
1694 if (projectdirection)
1696 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1698 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1699 TriangleNormal(v[0], v[1], v[2], normal);
1700 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1702 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1703 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1704 surfacemask |= mask;
1707 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;
1708 shadowsides[numshadowsides] = mask;
1709 shadowsideslist[numshadowsides++] = t;
1716 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1718 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1719 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1721 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1722 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1723 surfacemask |= mask;
1726 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;
1727 shadowsides[numshadowsides] = mask;
1728 shadowsideslist[numshadowsides++] = t;
1736 // surface box not entirely inside light box, cull each triangle
1737 if (projectdirection)
1739 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1741 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1742 TriangleNormal(v[0], v[1], v[2], normal);
1743 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1744 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1746 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1747 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1748 surfacemask |= mask;
1751 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;
1752 shadowsides[numshadowsides] = mask;
1753 shadowsideslist[numshadowsides++] = t;
1760 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1762 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1763 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1764 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1766 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1767 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1768 surfacemask |= mask;
1771 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;
1772 shadowsides[numshadowsides] = mask;
1773 shadowsideslist[numshadowsides++] = t;
1782 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)
1784 int i, j, outtriangles = 0;
1785 int *outelement3i[6];
1786 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1788 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1789 // make sure shadowelements is big enough for this mesh
1790 if (maxshadowtriangles < outtriangles)
1791 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1793 // compute the offset and size of the separate index lists for each cubemap side
1795 for (i = 0;i < 6;i++)
1797 outelement3i[i] = shadowelements + outtriangles * 3;
1798 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1799 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1800 outtriangles += sidetotals[i];
1803 // gather up the (sparse) triangles into separate index lists for each cubemap side
1804 for (i = 0;i < numsidetris;i++)
1806 const int *element = elements + sidetris[i] * 3;
1807 for (j = 0;j < 6;j++)
1809 if (sides[i] & (1 << j))
1811 outelement3i[j][0] = element[0];
1812 outelement3i[j][1] = element[1];
1813 outelement3i[j][2] = element[2];
1814 outelement3i[j] += 3;
1819 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1822 static void R_Shadow_MakeTextures_MakeCorona(void)
1826 unsigned char pixels[32][32][4];
1827 for (y = 0;y < 32;y++)
1829 dy = (y - 15.5f) * (1.0f / 16.0f);
1830 for (x = 0;x < 32;x++)
1832 dx = (x - 15.5f) * (1.0f / 16.0f);
1833 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1834 a = bound(0, a, 255);
1835 pixels[y][x][0] = a;
1836 pixels[y][x][1] = a;
1837 pixels[y][x][2] = a;
1838 pixels[y][x][3] = 255;
1841 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, false);
1844 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1846 float dist = sqrt(x*x+y*y+z*z);
1847 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1848 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1849 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1852 static void R_Shadow_MakeTextures(void)
1855 float intensity, dist;
1857 R_Shadow_FreeShadowMaps();
1858 R_FreeTexturePool(&r_shadow_texturepool);
1859 r_shadow_texturepool = R_AllocTexturePool();
1860 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1861 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1862 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1863 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1864 for (x = 0;x <= ATTENTABLESIZE;x++)
1866 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1867 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1868 r_shadow_attentable[x] = bound(0, intensity, 1);
1870 // 1D gradient texture
1871 for (x = 0;x < ATTEN1DSIZE;x++)
1872 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1873 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1874 // 2D circle texture
1875 for (y = 0;y < ATTEN2DSIZE;y++)
1876 for (x = 0;x < ATTEN2DSIZE;x++)
1877 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);
1878 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1879 // 3D sphere texture
1880 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1882 for (z = 0;z < ATTEN3DSIZE;z++)
1883 for (y = 0;y < ATTEN3DSIZE;y++)
1884 for (x = 0;x < ATTEN3DSIZE;x++)
1885 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));
1886 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);
1889 r_shadow_attenuation3dtexture = NULL;
1892 R_Shadow_MakeTextures_MakeCorona();
1894 // Editor light sprites
1895 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1912 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1913 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1930 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1931 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1948 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1949 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1966 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1967 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1984 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1985 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
2002 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
2005 void R_Shadow_ValidateCvars(void)
2007 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
2008 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
2009 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
2010 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
2011 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
2012 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
2015 void R_Shadow_RenderMode_Begin(void)
2021 R_Shadow_ValidateCvars();
2023 if (!r_shadow_attenuation2dtexture
2024 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
2025 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
2026 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
2027 R_Shadow_MakeTextures();
2030 R_Mesh_ResetTextureState();
2031 GL_BlendFunc(GL_ONE, GL_ZERO);
2032 GL_DepthRange(0, 1);
2033 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
2035 GL_DepthMask(false);
2036 GL_Color(0, 0, 0, 1);
2037 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2039 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2041 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
2043 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
2044 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
2046 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
2048 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
2049 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
2053 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
2054 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
2057 switch(vid.renderpath)
2059 case RENDERPATH_GL20:
2060 case RENDERPATH_D3D9:
2061 case RENDERPATH_D3D10:
2062 case RENDERPATH_D3D11:
2063 case RENDERPATH_SOFT:
2064 case RENDERPATH_GLES2:
2065 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
2067 case RENDERPATH_GL11:
2068 case RENDERPATH_GL13:
2069 case RENDERPATH_GLES1:
2070 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
2071 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
2072 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
2073 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
2074 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
2075 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
2077 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
2083 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
2084 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
2085 r_shadow_drawbuffer = drawbuffer;
2086 r_shadow_readbuffer = readbuffer;
2088 r_shadow_cullface_front = r_refdef.view.cullface_front;
2089 r_shadow_cullface_back = r_refdef.view.cullface_back;
2092 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
2094 rsurface.rtlight = rtlight;
2097 void R_Shadow_RenderMode_Reset(void)
2099 R_Mesh_ResetTextureState();
2100 R_Mesh_SetRenderTargets(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture, NULL, NULL, NULL);
2101 R_SetViewport(&r_refdef.view.viewport);
2102 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
2103 GL_DepthRange(0, 1);
2105 GL_DepthMask(false);
2106 GL_DepthFunc(GL_LEQUAL);
2107 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2108 r_refdef.view.cullface_front = r_shadow_cullface_front;
2109 r_refdef.view.cullface_back = r_shadow_cullface_back;
2110 GL_CullFace(r_refdef.view.cullface_back);
2111 GL_Color(1, 1, 1, 1);
2112 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2113 GL_BlendFunc(GL_ONE, GL_ZERO);
2114 R_SetupShader_Generic_NoTexture(false, false);
2115 r_shadow_usingshadowmap2d = false;
2116 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2119 void R_Shadow_ClearStencil(void)
2121 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2122 r_refdef.stats[r_stat_lights_clears]++;
2125 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2127 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2128 if (r_shadow_rendermode == mode)
2130 R_Shadow_RenderMode_Reset();
2131 GL_DepthFunc(GL_LESS);
2132 GL_ColorMask(0, 0, 0, 0);
2133 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2134 GL_CullFace(GL_NONE);
2135 R_SetupShader_DepthOrShadow(false, false, false); // FIXME test if we have a skeletal model?
2136 r_shadow_rendermode = mode;
2141 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2142 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2143 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2145 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2146 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2147 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2152 static void R_Shadow_MakeVSDCT(void)
2154 // maps to a 2x3 texture rectangle with normalized coordinates
2159 // stores abs(dir.xy), offset.xy/2.5
2160 unsigned char data[4*6] =
2162 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2163 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2164 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2165 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2166 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2167 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2169 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2172 static void R_Shadow_MakeShadowMap(int texturesize)
2174 switch (r_shadow_shadowmode)
2176 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2177 if (r_shadow_shadowmap2ddepthtexture) return;
2178 if (r_fb.usedepthtextures)
2180 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);
2181 r_shadow_shadowmap2ddepthbuffer = NULL;
2182 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2186 r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", texturesize, texturesize, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2187 r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
2188 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2196 void R_Shadow_ClearShadowMapTexture(void)
2198 r_viewport_t viewport;
2199 float clearcolor[4];
2201 // if they don't exist, create our textures now
2202 if (!r_shadow_shadowmap2ddepthtexture)
2203 R_Shadow_MakeShadowMap(r_shadow_shadowmaptexturesize);
2204 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2205 R_Shadow_MakeVSDCT();
2207 // we're setting up to render shadowmaps, so change rendermode
2208 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2210 R_Mesh_ResetTextureState();
2211 R_Shadow_RenderMode_Reset();
2212 if (r_shadow_shadowmap2ddepthbuffer)
2213 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2215 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2216 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2217 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2221 // we have to set a viewport to clear anything in some renderpaths (D3D)
2222 R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize, 0, 0, 1.0, 1.0, 0.001f, 1.0f, NULL);
2223 R_SetViewport(&viewport);
2224 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2225 if (r_shadow_shadowmap2ddepthbuffer)
2226 GL_ColorMask(1, 1, 1, 1);
2228 GL_ColorMask(0, 0, 0, 0);
2229 switch (vid.renderpath)
2231 case RENDERPATH_GL11:
2232 case RENDERPATH_GL13:
2233 case RENDERPATH_GL20:
2234 case RENDERPATH_SOFT:
2235 case RENDERPATH_GLES1:
2236 case RENDERPATH_GLES2:
2237 GL_CullFace(r_refdef.view.cullface_back);
2239 case RENDERPATH_D3D9:
2240 case RENDERPATH_D3D10:
2241 case RENDERPATH_D3D11:
2242 // we invert the cull mode because we flip the projection matrix
2243 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2244 GL_CullFace(r_refdef.view.cullface_front);
2247 Vector4Set(clearcolor, 1, 1, 1, 1);
2248 if (r_shadow_shadowmap2ddepthbuffer)
2249 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2251 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2254 static void R_Shadow_SetShadowmapParametersForLight(qboolean noselfshadowpass)
2256 int size = rsurface.rtlight->shadowmapatlassidesize;
2257 float nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2258 float farclip = 1.0f;
2259 float bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2260 r_shadow_lightshadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
2261 r_shadow_lightshadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
2262 r_shadow_lightshadowmap_texturescale[2] = rsurface.rtlight->shadowmapatlasposition[0] + (noselfshadowpass ? size * 2 : 0);
2263 r_shadow_lightshadowmap_texturescale[3] = rsurface.rtlight->shadowmapatlasposition[1];
2264 r_shadow_lightshadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2265 r_shadow_lightshadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2266 r_shadow_lightshadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2267 r_shadow_lightshadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2268 if (r_shadow_shadowmap2ddepthbuffer)
2270 // completely different meaning than in depthtexture approach
2271 r_shadow_lightshadowmap_parameters[1] = 0;
2272 r_shadow_lightshadowmap_parameters[3] = -bias;
2276 static void R_Shadow_RenderMode_ShadowMap(int side, int size, int x, int y)
2278 float nearclip, farclip, bias;
2279 r_viewport_t viewport;
2281 float clearcolor[4];
2283 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_SHADOWMAP2D)
2285 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2287 R_Mesh_ResetTextureState();
2288 R_Shadow_RenderMode_Reset();
2289 if (r_shadow_shadowmap2ddepthbuffer)
2290 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2292 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2293 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2294 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2299 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2301 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2303 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
2304 R_SetViewport(&viewport);
2305 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2306 flipped = (side & 1) ^ (side >> 2);
2307 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2308 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2310 Vector4Set(clearcolor, 1,1,1,1);
2311 if (r_shadow_shadowmap2ddepthbuffer)
2312 GL_ColorMask(1,1,1,1);
2314 GL_ColorMask(0,0,0,0);
2315 switch(vid.renderpath)
2317 case RENDERPATH_GL11:
2318 case RENDERPATH_GL13:
2319 case RENDERPATH_GL20:
2320 case RENDERPATH_SOFT:
2321 case RENDERPATH_GLES1:
2322 case RENDERPATH_GLES2:
2323 GL_CullFace(r_refdef.view.cullface_back);
2325 case RENDERPATH_D3D9:
2326 case RENDERPATH_D3D10:
2327 case RENDERPATH_D3D11:
2328 // we invert the cull mode because we flip the projection matrix
2329 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2330 GL_CullFace(r_refdef.view.cullface_front);
2334 // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
2335 r_shadow_shadowmapside = side;
2338 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass)
2340 R_Mesh_ResetTextureState();
2343 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2344 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2345 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2346 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2349 R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
2350 R_Shadow_RenderMode_Reset();
2351 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2353 GL_DepthFunc(GL_EQUAL);
2354 // do global setup needed for the chosen lighting mode
2355 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2356 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2357 r_shadow_usingshadowmap2d = shadowmapping;
2358 r_shadow_rendermode = r_shadow_lightingrendermode;
2359 // only draw light where this geometry was already rendered AND the
2360 // stencil is 128 (values other than this mean shadow)
2362 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2364 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2367 static const unsigned short bboxelements[36] =
2377 static const float bboxpoints[8][3] =
2389 void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping)
2392 float vertex3f[8*3];
2393 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2394 // do global setup needed for the chosen lighting mode
2395 R_Shadow_RenderMode_Reset();
2396 r_shadow_rendermode = r_shadow_lightingrendermode;
2397 R_EntityMatrix(&identitymatrix);
2398 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2399 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2400 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
2401 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2403 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
2405 r_shadow_usingshadowmap2d = shadowmapping;
2407 // render the lighting
2408 R_SetupShader_DeferredLight(rsurface.rtlight);
2409 for (i = 0;i < 8;i++)
2410 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2411 GL_ColorMask(1,1,1,1);
2412 GL_DepthMask(false);
2413 GL_DepthRange(0, 1);
2414 GL_PolygonOffset(0, 0);
2416 GL_DepthFunc(GL_GREATER);
2417 GL_CullFace(r_refdef.view.cullface_back);
2418 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
2419 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2422 #define MAXBOUNCEGRIDSPLATSIZE 7
2423 #define MAXBOUNCEGRIDSPLATSIZE1 (MAXBOUNCEGRIDSPLATSIZE+1)
2425 // these are temporary data per-frame, sorted and performed in a more
2426 // cache-friendly order than the original photons
2427 typedef struct r_shadow_bouncegrid_splatpath_s
2433 vec_t splatintensity;
2434 vec_t splatsize_current;
2435 vec_t splatsize_perstep;
2436 int remainingsplats;
2438 r_shadow_bouncegrid_splatpath_t;
2440 static void R_Shadow_BounceGrid_AddSplatPath(vec3_t originalstart, vec3_t originalend, vec3_t color, vec_t distancetraveled)
2450 r_shadow_bouncegrid_splatpath_t *path;
2452 // cull paths that fail R_CullBox in dynamic mode
2453 if (!r_shadow_bouncegrid_state.settings.staticmode
2454 && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
2456 vec3_t cullmins, cullmaxs;
2457 cullmins[0] = min(originalstart[0], originalend[0]) - r_shadow_bouncegrid_state.settings.spacing[0];
2458 cullmins[1] = min(originalstart[1], originalend[1]) - r_shadow_bouncegrid_state.settings.spacing[1];
2459 cullmins[2] = min(originalstart[2], originalend[2]) - r_shadow_bouncegrid_state.settings.spacing[2];
2460 cullmaxs[0] = max(originalstart[0], originalend[0]) + r_shadow_bouncegrid_state.settings.spacing[0];
2461 cullmaxs[1] = max(originalstart[1], originalend[1]) + r_shadow_bouncegrid_state.settings.spacing[1];
2462 cullmaxs[2] = max(originalstart[2], originalend[2]) + r_shadow_bouncegrid_state.settings.spacing[2];
2463 if (R_CullBox(cullmins, cullmaxs))
2467 // if the light path is going upward, reverse it - we always draw down.
2468 if (originalend[2] < originalstart[2])
2470 VectorCopy(originalend, start);
2471 VectorCopy(originalstart, end);
2475 VectorCopy(originalstart, start);
2476 VectorCopy(originalend, end);
2479 // transform to texture pixels
2480 start[0] = (start[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2481 start[1] = (start[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2482 start[2] = (start[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2483 end[0] = (end[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2484 end[1] = (end[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2485 end[2] = (end[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2487 // check if we need to grow the splatpaths array
2488 if (r_shadow_bouncegrid_state.maxsplatpaths <= r_shadow_bouncegrid_state.numsplatpaths)
2490 // double the limit, this will persist from frame to frame so we don't
2491 // make the same mistake each time
2492 r_shadow_bouncegrid_state.maxsplatpaths *= 2;
2493 if (r_shadow_bouncegrid_state.maxsplatpaths < 16384)
2494 r_shadow_bouncegrid_state.maxsplatpaths = 16384;
2495 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);
2498 // divide a series of splats along the length using the maximum axis
2499 VectorSubtract(end, start, diff);
2500 // pick the best axis to trace along
2502 if (diff[1]*diff[1] > diff[bestaxis]*diff[bestaxis])
2504 if (diff[2]*diff[2] > diff[bestaxis]*diff[bestaxis])
2506 len = fabs(diff[bestaxis]);
2508 numsplats = (int)(floor(len + 0.5f));
2510 numsplats = bound(0, numsplats, 1024);
2512 VectorSubtract(originalstart, originalend, originaldir);
2513 VectorNormalize(originaldir);
2515 path = r_shadow_bouncegrid_state.splatpaths + r_shadow_bouncegrid_state.numsplatpaths++;
2516 VectorCopy(start, path->point);
2517 VectorScale(diff, ilen, path->step);
2518 VectorCopy(color, path->splatcolor);
2519 VectorCopy(originaldir, path->splatdir);
2520 path->splatsize_current = r_shadow_bouncegrid_state.settings.lightpathsize_initial + r_shadow_bouncegrid_state.settings.lightpathsize_conespread * distancetraveled * r_shadow_bouncegrid_state.ispacing[0];
2521 path->splatsize_perstep = r_shadow_bouncegrid_state.settings.lightpathsize_conespread;
2522 path->splatintensity = VectorLength(color);
2523 path->remainingsplats = numsplats;
2526 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
2528 qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
2535 // see if there are really any lights to render...
2536 if (enable && r_shadow_bouncegrid_static.integer)
2539 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2540 for (lightindex = 0;lightindex < range;lightindex++)
2542 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2543 if (!light || !(light->flags & flag))
2545 rtlight = &light->rtlight;
2546 // when static, we skip styled lights because they tend to change...
2547 if (rtlight->style > 0)
2549 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
2550 if (!VectorLength2(lightcolor))
2560 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
2562 qboolean s = r_shadow_bouncegrid_static.integer != 0;
2563 float spacing = bound(1.0f, s ? r_shadow_bouncegrid_static_spacing.value : r_shadow_bouncegrid_dynamic_spacing.value, 1024.0f);
2564 float quality = bound(0.0001f, (s ? r_shadow_bouncegrid_static_quality.value : r_shadow_bouncegrid_dynamic_quality.value), 1024.0f);
2565 float bounceminimumintensity = s ? r_shadow_bouncegrid_static_bounceminimumintensity.value : r_shadow_bouncegrid_dynamic_bounceminimumintensity.value;
2567 // prevent any garbage in alignment padded areas as we'll be using memcmp
2568 memset(settings, 0, sizeof(*settings));
2570 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
2571 settings->staticmode = s;
2572 settings->blur = r_shadow_bouncegrid_blur.integer != 0;
2573 settings->floatcolors = bound(0, r_shadow_bouncegrid_floatcolors.integer, 2);
2574 settings->lightpathsize_initial = bound(0.0f, r_shadow_bouncegrid_lightpathsize_initial.value, 1024.0f);
2575 settings->lightpathsize_conespread = bound(0.0f, r_shadow_bouncegrid_lightpathsize_conespread.value, 1024.0f);
2576 settings->bounceanglediffuse = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
2577 settings->directionalshading = (s ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_dynamic_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
2578 settings->dlightparticlemultiplier = s ? 0 : r_shadow_bouncegrid_dynamic_dlightparticlemultiplier.value;
2579 settings->hitmodels = s ? false : r_shadow_bouncegrid_dynamic_hitmodels.integer != 0;
2580 settings->includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
2581 settings->lightradiusscale = (s ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_dynamic_lightradiusscale.value);
2582 settings->maxbounce = (s ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_dynamic_maxbounce.integer);
2583 settings->particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
2584 settings->particleintensity = r_shadow_bouncegrid_particleintensity.value * (settings->directionalshading ? 4.0f : 1.0f) * 16384 / (spacing * spacing) / 262144.0f;
2585 settings->maxphotons = s ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_dynamic_maxphotons.integer;
2586 settings->energyperphoton = spacing * spacing / quality;
2587 settings->spacing[0] = spacing;
2588 settings->spacing[1] = spacing;
2589 settings->spacing[2] = spacing;
2590 settings->rng_type = r_shadow_bouncegrid_rng_type.integer;
2591 settings->rng_seed = r_shadow_bouncegrid_rng_seed.integer;
2592 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
2593 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
2594 settings->normalizevectors = r_shadow_bouncegrid_normalizevectors.integer != 0;
2596 // bound the values for sanity
2597 settings->maxphotons = bound(1, settings->maxphotons, 25000000);
2598 settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
2599 settings->maxbounce = bound(0, settings->maxbounce, 16);
2600 settings->spacing[0] = bound(1, settings->spacing[0], 512);
2601 settings->spacing[1] = bound(1, settings->spacing[1], 512);
2602 settings->spacing[2] = bound(1, settings->spacing[2], 512);
2605 static void R_Shadow_BounceGrid_UpdateSpacing(void)
2616 r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
2618 // get the spacing values
2619 spacing[0] = settings->spacing[0];
2620 spacing[1] = settings->spacing[1];
2621 spacing[2] = settings->spacing[2];
2622 ispacing[0] = 1.0f / spacing[0];
2623 ispacing[1] = 1.0f / spacing[1];
2624 ispacing[2] = 1.0f / spacing[2];
2626 // calculate texture size enclosing entire world bounds at the spacing
2627 if (r_refdef.scene.worldmodel)
2629 VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
2630 VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
2634 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
2635 VectorSet(maxs, 1048576.0f, 1048576.0f, 1048576.0f);
2637 VectorSubtract(maxs, mins, size);
2638 // now we can calculate the resolution we want
2639 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2640 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2641 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2642 // figure out the exact texture size (honoring power of 2 if required)
2643 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2644 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2645 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2646 if (vid.support.arb_texture_non_power_of_two)
2648 resolution[0] = c[0];
2649 resolution[1] = c[1];
2650 resolution[2] = c[2];
2654 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2655 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2656 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2658 size[0] = spacing[0] * resolution[0];
2659 size[1] = spacing[1] * resolution[1];
2660 size[2] = spacing[2] * resolution[2];
2662 // if dynamic we may or may not want to use the world bounds
2663 // if the dynamic size is smaller than the world bounds, use it instead
2664 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]))
2666 // we know the resolution we want
2667 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
2668 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
2669 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
2670 // now we can calculate the texture size (power of 2 if required)
2671 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2672 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2673 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2674 if (vid.support.arb_texture_non_power_of_two)
2676 resolution[0] = c[0];
2677 resolution[1] = c[1];
2678 resolution[2] = c[2];
2682 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2683 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2684 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2686 size[0] = spacing[0] * resolution[0];
2687 size[1] = spacing[1] * resolution[1];
2688 size[2] = spacing[2] * resolution[2];
2689 // center the rendering on the view
2690 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2691 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2692 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2695 // recalculate the maxs in case the resolution was not satisfactory
2696 VectorAdd(mins, size, maxs);
2698 // check if this changed the texture size
2699 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);
2700 r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
2701 VectorCopy(mins, r_shadow_bouncegrid_state.mins);
2702 VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
2703 VectorCopy(size, r_shadow_bouncegrid_state.size);
2704 VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
2705 VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
2706 VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
2708 // reallocate pixels for this update if needed...
2709 r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
2710 r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
2711 r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
2712 numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
2713 if (r_shadow_bouncegrid_state.numpixels != numpixels)
2715 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
2716 r_shadow_bouncegrid_state.highpixels = NULL;
2717 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2718 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2719 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2720 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2721 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2722 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2723 r_shadow_bouncegrid_state.numpixels = numpixels;
2726 // update the bouncegrid matrix to put it in the world properly
2727 memset(m, 0, sizeof(m));
2728 m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
2729 m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
2730 m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
2731 m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
2732 m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
2733 m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
2735 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
2738 // enumerate world rtlights and sum the overall amount of light in the world,
2739 // from that we can calculate a scaling factor to fairly distribute photons
2740 // to all the lights
2742 // this modifies rtlight->photoncolor and rtlight->photons
2743 static void R_Shadow_BounceGrid_AssignPhotons(r_shadow_bouncegrid_settings_t *settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
2745 float normalphotonscaling;
2746 float photonscaling;
2747 float photonintensity;
2748 float photoncount = 0.0f;
2749 float lightintensity;
2755 unsigned int lightindex;
2758 normalphotonscaling = 1.0f / max(0.0001f, settings->energyperphoton);
2759 for (lightindex = 0;lightindex < range2;lightindex++)
2761 if (lightindex < range)
2763 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2766 rtlight = &light->rtlight;
2767 VectorClear(rtlight->bouncegrid_photoncolor);
2768 rtlight->bouncegrid_photons = 0;
2769 rtlight->bouncegrid_hits = 0;
2770 rtlight->bouncegrid_traces = 0;
2771 rtlight->bouncegrid_effectiveradius = 0;
2772 if (!(light->flags & flag))
2774 if (settings->staticmode)
2776 // when static, we skip styled lights because they tend to change...
2777 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2780 else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
2785 rtlight = r_refdef.scene.lights[lightindex - range];
2786 VectorClear(rtlight->bouncegrid_photoncolor);
2787 rtlight->bouncegrid_photons = 0;
2788 rtlight->bouncegrid_hits = 0;
2789 rtlight->bouncegrid_traces = 0;
2790 rtlight->bouncegrid_effectiveradius = 0;
2792 // draw only visible lights (major speedup)
2793 radius = rtlight->radius * settings->lightradiusscale;
2794 cullmins[0] = rtlight->shadoworigin[0] - radius;
2795 cullmins[1] = rtlight->shadoworigin[1] - radius;
2796 cullmins[2] = rtlight->shadoworigin[2] - radius;
2797 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2798 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2799 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2800 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2801 if (!settings->staticmode)
2803 if (R_CullBox(cullmins, cullmaxs))
2805 if (r_refdef.scene.worldmodel
2806 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2807 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2809 if (w * VectorLength2(rtlight->color) == 0.0f)
2812 // a light that does not emit any light before style is applied, can be
2813 // skipped entirely (it may just be a corona)
2814 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2816 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2817 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2818 // skip lights that will emit no photons
2819 if (!VectorLength2(rtlight->bouncegrid_photoncolor))
2821 // shoot particles from this light
2822 // use a calculation for the number of particles that will not
2823 // vary with lightstyle, otherwise we get randomized particle
2824 // distribution, the seeded random is only consistent for a
2825 // consistent number of particles on this light...
2826 s = rtlight->radius;
2827 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2828 if (lightindex >= range)
2829 lightintensity *= settings->dlightparticlemultiplier;
2830 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2831 photoncount += rtlight->bouncegrid_photons;
2832 VectorScale(rtlight->bouncegrid_photoncolor, settings->particleintensity * settings->energyperphoton, rtlight->bouncegrid_photoncolor);
2833 // if the lightstyle happens to be off right now, we can skip actually
2834 // firing the photons, but we did have to count them in the total.
2835 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2836 // rtlight->bouncegrid_photons = 0;
2838 // the user provided an energyperphoton value which we try to use
2839 // if that results in too many photons to shoot this frame, then we cap it
2840 // which causes photons to appear/disappear from frame to frame, so we don't
2841 // like doing that in the typical case
2842 photonscaling = 1.0f;
2843 photonintensity = 1.0f;
2844 if (photoncount > settings->maxphotons)
2846 photonscaling = settings->maxphotons / photoncount;
2847 photonintensity = 1.0f / photonscaling;
2850 // modify the lights to reflect our computed scaling
2851 for (lightindex = 0; lightindex < range2; lightindex++)
2853 if (lightindex < range)
2855 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2858 rtlight = &light->rtlight;
2861 rtlight = r_refdef.scene.lights[lightindex - range];
2862 rtlight->bouncegrid_photons *= photonscaling;
2863 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2867 static int R_Shadow_BounceGrid_SplatPathCompare(const void *pa, const void *pb)
2869 r_shadow_bouncegrid_splatpath_t *a = (r_shadow_bouncegrid_splatpath_t *)pa;
2870 r_shadow_bouncegrid_splatpath_t *b = (r_shadow_bouncegrid_splatpath_t *)pb;
2871 // we only really care about sorting by Z
2872 if (a->point[2] < b->point[2])
2874 if (a->point[2] > b->point[2])
2879 static void R_Shadow_BounceGrid_ClearPixels(void)
2881 // clear the highpixels array we'll be accumulating into
2882 if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2883 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2884 if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2885 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2886 r_shadow_bouncegrid_state.highpixels_index = 0;
2887 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2888 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2891 static void R_Shadow_BounceGrid_PerformSplats(void)
2893 r_shadow_bouncegrid_splatpath_t *splatpaths = r_shadow_bouncegrid_state.splatpaths;
2894 r_shadow_bouncegrid_splatpath_t *splatpath;
2895 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2896 int numsplatpaths = r_shadow_bouncegrid_state.numsplatpaths;
2901 vec_t lightpathsize_current;
2902 vec_t lightpathsize_perstep;
2903 float splatcolor[32];
2905 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2906 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2910 // hush warnings about uninitialized data - pixelbands doesn't change but...
2911 memset(splatcolor, 0, sizeof(splatcolor));
2913 // we use this a lot, so get a local copy
2914 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2916 // sort the splats before we execute them, to reduce cache misses
2917 if (r_shadow_bouncegrid_sortlightpaths.integer)
2918 qsort(splatpaths, numsplatpaths, sizeof(*splatpaths), R_Shadow_BounceGrid_SplatPathCompare);
2920 splatpath = splatpaths;
2921 for (splatindex = 0;splatindex < numsplatpaths;splatindex++, splatpath++)
2923 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2924 // accumulate average shotcolor
2925 VectorCopy(splatpath->splatdir, dir);
2926 splatcolor[ 0] = splatpath->splatcolor[0];
2927 splatcolor[ 1] = splatpath->splatcolor[1];
2928 splatcolor[ 2] = splatpath->splatcolor[2];
2929 splatcolor[ 3] = 0.0f;
2932 // store bentnormal in case the shader has a use for it,
2933 // bentnormal is an intensity-weighted average of the directions,
2934 // and will be normalized on conversion to texture pixels.
2935 splatcolor[ 4] = dir[0] * splatpath->splatintensity;
2936 splatcolor[ 5] = dir[1] * splatpath->splatintensity;
2937 splatcolor[ 6] = dir[2] * splatpath->splatintensity;
2938 splatcolor[ 7] = splatpath->splatintensity;
2939 // for each color component (R, G, B) calculate the amount that a
2940 // direction contributes
2941 splatcolor[ 8] = splatcolor[0] * max(0.0f, dir[0]);
2942 splatcolor[ 9] = splatcolor[0] * max(0.0f, dir[1]);
2943 splatcolor[10] = splatcolor[0] * max(0.0f, dir[2]);
2944 splatcolor[11] = 0.0f;
2945 splatcolor[12] = splatcolor[1] * max(0.0f, dir[0]);
2946 splatcolor[13] = splatcolor[1] * max(0.0f, dir[1]);
2947 splatcolor[14] = splatcolor[1] * max(0.0f, dir[2]);
2948 splatcolor[15] = 0.0f;
2949 splatcolor[16] = splatcolor[2] * max(0.0f, dir[0]);
2950 splatcolor[17] = splatcolor[2] * max(0.0f, dir[1]);
2951 splatcolor[18] = splatcolor[2] * max(0.0f, dir[2]);
2952 splatcolor[19] = 0.0f;
2953 // and do the same for negative directions
2954 splatcolor[20] = splatcolor[0] * max(0.0f, -dir[0]);
2955 splatcolor[21] = splatcolor[0] * max(0.0f, -dir[1]);
2956 splatcolor[22] = splatcolor[0] * max(0.0f, -dir[2]);
2957 splatcolor[23] = 0.0f;
2958 splatcolor[24] = splatcolor[1] * max(0.0f, -dir[0]);
2959 splatcolor[25] = splatcolor[1] * max(0.0f, -dir[1]);
2960 splatcolor[26] = splatcolor[1] * max(0.0f, -dir[2]);
2961 splatcolor[27] = 0.0f;
2962 splatcolor[28] = splatcolor[2] * max(0.0f, -dir[0]);
2963 splatcolor[29] = splatcolor[2] * max(0.0f, -dir[1]);
2964 splatcolor[30] = splatcolor[2] * max(0.0f, -dir[2]);
2965 splatcolor[31] = 0.0f;
2967 // calculate the number of steps we need to traverse this distance
2968 VectorCopy(splatpath->point, steppos);
2969 VectorCopy(splatpath->step, stepdelta);
2970 numsteps = splatpath->remainingsplats;
2971 lightpathsize_current = splatpath->splatsize_current + 1.0f; // add 1.0 for the gradient fade around the sphere
2972 lightpathsize_perstep = splatpath->splatsize_perstep;
2973 for (step = 0;step < numsteps;step++)
2975 // the middle row/column/layer of each splat are full intensity
2978 if (lightpathsize_current > MAXBOUNCEGRIDSPLATSIZE)
2979 lightpathsize_current = MAXBOUNCEGRIDSPLATSIZE;
2980 splatmins[0] = max(1.0f, steppos[0] - lightpathsize_current * 0.5f);
2981 splatmins[1] = max(1.0f, steppos[1] - lightpathsize_current * 0.5f);
2982 splatmins[2] = max(1.0f, steppos[2] - lightpathsize_current * 0.5f);
2983 splatmaxs[0] = min(steppos[0] + lightpathsize_current * 0.5f, resolution[0] - 1.0f);
2984 splatmaxs[1] = min(steppos[1] + lightpathsize_current * 0.5f, resolution[1] - 1.0f);
2985 splatmaxs[2] = min(steppos[2] + lightpathsize_current * 0.5f, resolution[2] - 1.0f);
2986 if (splatmaxs[0] > splatmins[0] && splatmaxs[1] > splatmins[1] && splatmaxs[2] > splatmins[2])
2988 // it is within bounds... do the real work now
2989 int xi, yi, zi, band, row;
2993 float colorscale = 1.0f / lightpathsize_current;
2994 r_refdef.stats[r_stat_bouncegrid_splats]++;
2995 // accumulate light onto the pixels
2996 for (zi = (int)floor(splatmins[2]);zi < splatmaxs[2];zi++)
2998 pixelpos[2] = zi + 0.5f;
2999 for (yi = (int)floor(splatmins[1]); yi < splatmaxs[1]; yi++)
3001 pixelpos[1] = yi + 0.5f;
3002 row = (zi*resolution[1] + yi)*resolution[0];
3003 for (xi = (int)floor(splatmins[0]); xi < splatmaxs[0]; xi++)
3005 pixelpos[0] = xi + 0.5f;
3006 // simple radial antialiased sphere - linear gradient fade over 1 pixel from the edge
3007 w = lightpathsize_current - VectorDistance(pixelpos, steppos);
3013 p = highpixels + 4 * (row + xi);
3014 for (band = 0; band < pixelbands; band++, p += pixelsperband * 4)
3016 // add to the pixel color
3017 p[0] += splatcolor[band * 4 + 0] * w;
3018 p[1] += splatcolor[band * 4 + 1] * w;
3019 p[2] += splatcolor[band * 4 + 2] * w;
3020 p[3] += splatcolor[band * 4 + 3] * w;
3027 VectorAdd(steppos, stepdelta, steppos);
3028 lightpathsize_current += lightpathsize_perstep;
3033 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
3035 const float *inpixel;
3037 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
3040 unsigned int x, y, z;
3041 unsigned int resolution[3];
3042 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3043 for (pixelband = 0;pixelband < pixelbands;pixelband++)
3045 for (z = 1;z < resolution[2]-1;z++)
3047 for (y = 1;y < resolution[1]-1;y++)
3050 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3051 inpixel = inpixels + 4*index;
3052 outpixel = outpixels + 4*index;
3053 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
3055 outpixel[0] = (inpixel[0] + inpixel[ off] + inpixel[0-off]) * (1.0f / 3.0);
3056 outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
3057 outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
3058 outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
3065 static void R_Shadow_BounceGrid_BlurPixels(void)
3068 unsigned int resolution[3];
3070 if (!r_shadow_bouncegrid_state.settings.blur)
3073 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3075 pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3076 pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
3077 pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3078 pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
3081 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
3083 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
3085 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
3087 // toggle the state, highpixels now points to pixels[3] result
3088 r_shadow_bouncegrid_state.highpixels_index ^= 1;
3089 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3092 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
3094 int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
3095 unsigned char *pixelsbgra8 = NULL;
3096 unsigned char *pixelbgra8;
3097 unsigned short *pixelsrgba16f = NULL;
3098 unsigned short *pixelrgba16f;
3099 float *pixelsrgba32f = NULL;
3100 float *highpixels = r_shadow_bouncegrid_state.highpixels;
3103 unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
3104 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
3105 unsigned int pixelband;
3106 unsigned int x, y, z;
3107 unsigned int index, bandindex;
3108 unsigned int resolution[3];
3110 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3112 if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
3114 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3115 r_shadow_bouncegrid_state.texture = NULL;
3118 // if bentnormals exist, we need to normalize and bias them for the shader
3122 for (z = 0;z < resolution[2]-1;z++)
3124 for (y = 0;y < resolution[1]-1;y++)
3127 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3128 highpixel = highpixels + 4*index;
3129 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3131 // only convert pixels that were hit by photons
3132 if (highpixel[3] != 0.0f)
3133 VectorNormalize(highpixel);
3134 VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
3135 highpixel[pixelsperband * 4 + 3] = 1.0f;
3141 // start by clearing the pixels array - we won't be writing to all of it
3143 // then process only the pixels that have at least some color, skipping
3144 // the higher bands for speed on pixels that are black
3145 switch (floatcolors)
3148 if (r_shadow_bouncegrid_state.u8pixels == NULL)
3149 r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
3150 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
3151 for (pixelband = 0;pixelband < pixelbands;pixelband++)
3154 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
3156 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
3158 for (z = 1;z < resolution[2]-1;z++)
3160 for (y = 1;y < resolution[1]-1;y++)
3164 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3165 highpixel = highpixels + 4*index;
3166 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3168 // only convert pixels that were hit by photons
3169 if (VectorLength2(highpixel))
3171 // normalize the bentnormal now
3174 VectorNormalize(highpixel + pixelsperband * 4);
3175 highpixel[pixelsperband * 4 + 3] = 1.0f;
3177 // process all of the pixelbands for this pixel
3178 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3180 pixelbgra8 = pixelsbgra8 + 4*bandindex;
3181 bandpixel = highpixels + 4*bandindex;
3182 c[0] = (int)(bandpixel[0]*256.0f);
3183 c[1] = (int)(bandpixel[1]*256.0f);
3184 c[2] = (int)(bandpixel[2]*256.0f);
3185 c[3] = (int)(bandpixel[3]*256.0f);
3186 pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
3187 pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
3188 pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
3189 pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
3196 if (!r_shadow_bouncegrid_state.createtexture)
3197 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3199 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);
3202 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
3203 r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3204 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
3205 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3206 for (z = 1;z < resolution[2]-1;z++)
3208 for (y = 1;y < resolution[1]-1;y++)
3212 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3213 highpixel = highpixels + 4*index;
3214 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3216 // only convert pixels that were hit by photons
3217 if (VectorLength2(highpixel))
3219 // process all of the pixelbands for this pixel
3220 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3222 // time to have fun with IEEE 754 bit hacking...
3225 unsigned int raw[4];
3227 pixelrgba16f = pixelsrgba16f + 4*bandindex;
3228 bandpixel = highpixels + 4*bandindex;
3229 VectorCopy4(bandpixel, u.f);
3230 VectorCopy4(u.raw, c);
3231 // this math supports negative numbers, snaps denormals to zero
3232 //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
3233 //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
3234 //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
3235 //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
3236 // this math does not support negative
3237 pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
3238 pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
3239 pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
3240 pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
3247 if (!r_shadow_bouncegrid_state.createtexture)
3248 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3250 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);
3253 // our native format happens to match, so this is easy.
3254 pixelsrgba32f = highpixels;
3256 if (!r_shadow_bouncegrid_state.createtexture)
3257 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3259 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);
3263 r_shadow_bouncegrid_state.lastupdatetime = realtime;
3266 static void R_Shadow_BounceGrid_TracePhotons(r_shadow_bouncegrid_settings_t settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
3268 vec3_t bouncerandom[10];
3271 int hitsupercontentsmask;
3272 int skipsupercontentsmask;
3276 float bounceminimumintensity2;
3278 //trace_t cliptrace2;
3279 //trace_t cliptrace3;
3280 unsigned int lightindex;
3282 randomseed_t randomseed;
3284 vec3_t baseshotcolor;
3290 vec_t distancetraveled;
3294 // compute a seed for the unstable random modes
3295 Math_RandomSeed_FromInts(&randomseed, 0, 0, 0, realtime * 1000.0);
3296 seed = realtime * 1000.0;
3298 r_shadow_bouncegrid_state.numsplatpaths = 0;
3300 // figure out what we want to interact with
3301 if (settings.hitmodels)
3302 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;// | SUPERCONTENTS_LIQUIDSMASK;
3304 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
3305 skipsupercontentsmask = SUPERCONTENTS_SKY; // this allows the e1m5 sky shadow to work by ignoring the sky surfaces
3306 maxbounce = settings.maxbounce;
3308 for (lightindex = 0;lightindex < range2;lightindex++)
3310 if (lightindex < range)
3312 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3315 rtlight = &light->rtlight;
3318 rtlight = r_refdef.scene.lights[lightindex - range];
3319 // note that this code used to keep track of residual photons and
3320 // distribute them evenly to achieve exactly a desired photon count,
3321 // but that caused unwanted flickering in dynamic mode
3322 shootparticles = (int)floor(rtlight->bouncegrid_photons);
3323 // skip if we won't be shooting any photons
3324 if (!shootparticles)
3326 radius = rtlight->radius * settings.lightradiusscale;
3327 //s = settings.particleintensity / shootparticles;
3328 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
3329 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
3330 if (VectorLength2(baseshotcolor) <= 0.0f)
3332 r_refdef.stats[r_stat_bouncegrid_lights]++;
3333 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
3334 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
3335 bounceminimumintensity2 = VectorLength(baseshotcolor) * settings.bounceminimumintensity2;
3337 // for seeded random we start the RNG with the position of the light
3338 if (settings.rng_seed >= 0)
3346 u.f[0] = rtlight->shadoworigin[0];
3347 u.f[1] = rtlight->shadoworigin[1];
3348 u.f[2] = rtlight->shadoworigin[2];
3350 switch (settings.rng_type)
3354 // we have to shift the seed provided by the user because the result must be odd
3355 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3] ^ (settings.rng_seed << 1));
3358 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3] ^ settings.rng_seed;
3363 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
3365 VectorCopy(baseshotcolor, shotcolor);
3366 VectorCopy(rtlight->shadoworigin, clipstart);
3367 switch (settings.rng_type)
3371 VectorLehmerRandom(&randomseed, clipend);
3372 if (settings.bounceanglediffuse)
3374 // we want random to be stable, so we still have to do all the random we would have done
3375 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3376 VectorLehmerRandom(&randomseed, bouncerandom[bouncecount]);
3380 VectorCheeseRandom(seed, 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 VectorCheeseRandom(seed, bouncerandom[bouncecount]);
3390 // we want a uniform distribution spherically, not merely within the sphere
3391 if (settings.normalizevectors)
3392 VectorNormalize(clipend);
3394 VectorMA(clipstart, radius, clipend, clipend);
3395 distancetraveled = 0.0f;
3396 for (bouncecount = 0;;bouncecount++)
3398 r_refdef.stats[r_stat_bouncegrid_traces]++;
3399 rtlight->bouncegrid_traces++;
3400 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
3401 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
3402 if (settings.staticmode || settings.rng_seed < 0)
3404 // static mode fires a LOT of rays but none of them are identical, so they are not cached
3405 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
3406 cliptrace = CL_TraceLine(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), NULL, hitsupercontentsmask, skipsupercontentsmask, collision_extendmovelength.value, true, false, NULL, true, true);
3410 // dynamic mode fires many rays and most will match the cache from the previous frame
3411 cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask, skipsupercontentsmask);
3413 if (bouncecount > 0 || settings.includedirectlighting)
3416 VectorCopy(cliptrace.endpos, hitpos);
3417 R_Shadow_BounceGrid_AddSplatPath(clipstart, hitpos, shotcolor, distancetraveled);
3419 distancetraveled += VectorDistance(clipstart, cliptrace.endpos);
3420 s = VectorDistance(rtlight->shadoworigin, cliptrace.endpos);
3421 if (rtlight->bouncegrid_effectiveradius < s)
3422 rtlight->bouncegrid_effectiveradius = s;
3423 if (cliptrace.fraction >= 1.0f)
3425 r_refdef.stats[r_stat_bouncegrid_hits]++;
3426 rtlight->bouncegrid_hits++;
3427 if (bouncecount >= maxbounce)
3429 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
3430 // also clamp the resulting color to never add energy, even if the user requests extreme values
3431 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
3432 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
3434 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
3435 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
3436 surfcolor[0] = min(surfcolor[0], 1.0f);
3437 surfcolor[1] = min(surfcolor[1], 1.0f);
3438 surfcolor[2] = min(surfcolor[2], 1.0f);
3439 VectorMultiply(shotcolor, surfcolor, shotcolor);
3440 if (VectorLength2(shotcolor) <= bounceminimumintensity2)
3442 r_refdef.stats[r_stat_bouncegrid_bounces]++;
3443 if (settings.bounceanglediffuse)
3445 // random direction, primarily along plane normal
3446 s = VectorDistance(cliptrace.endpos, clipend);
3447 VectorMA(cliptrace.plane.normal, 0.95f, bouncerandom[bouncecount], clipend);
3448 VectorNormalize(clipend);
3449 VectorScale(clipend, s, clipend);
3453 // reflect the remaining portion of the line across plane normal
3454 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
3455 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
3457 // calculate the new line start and end
3458 VectorCopy(cliptrace.endpos, clipstart);
3459 VectorAdd(clipstart, clipend, clipend);
3465 void R_Shadow_UpdateBounceGridTexture(void)
3467 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3468 r_shadow_bouncegrid_settings_t settings;
3469 qboolean enable = false;
3470 qboolean settingschanged;
3471 unsigned int range; // number of world lights
3472 unsigned int range1; // number of dynamic lights (or zero if disabled)
3473 unsigned int range2; // range+range1
3475 enable = R_Shadow_BounceGrid_CheckEnable(flag);
3477 R_Shadow_BounceGrid_GenerateSettings(&settings);
3479 // changing intensity does not require an update
3480 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
3482 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
3484 // when settings change, we free everything as it is just simpler that way.
3485 if (settingschanged || !enable)
3487 // not enabled, make sure we free anything we don't need anymore.
3488 if (r_shadow_bouncegrid_state.texture)
3490 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3491 r_shadow_bouncegrid_state.texture = NULL;
3493 r_shadow_bouncegrid_state.highpixels = NULL;
3494 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
3495 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
3496 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
3497 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
3498 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
3499 r_shadow_bouncegrid_state.maxsplatpaths = 0;
3500 r_shadow_bouncegrid_state.numpixels = 0;
3501 r_shadow_bouncegrid_state.directional = false;
3507 // if all the settings seem identical to the previous update, return
3508 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
3511 // store the new settings
3512 r_shadow_bouncegrid_state.settings = settings;
3514 R_Shadow_BounceGrid_UpdateSpacing();
3516 // get the range of light numbers we'll be looping over:
3517 // range = static lights
3518 // range1 = dynamic lights (optional)
3519 // range2 = range + range1
3520 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3521 range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
3522 range2 = range + range1;
3524 // calculate weighting factors for distributing photons among the lights
3525 R_Shadow_BounceGrid_AssignPhotons(&settings, range, range1, range2, flag);
3527 // trace the photons from lights and accumulate illumination
3528 R_Shadow_BounceGrid_TracePhotons(settings, range, range1, range2, flag);
3530 // clear the texture
3531 R_Shadow_BounceGrid_ClearPixels();
3533 // accumulate the light splatting into texture
3534 R_Shadow_BounceGrid_PerformSplats();
3536 // apply a mild blur filter to the texture
3537 R_Shadow_BounceGrid_BlurPixels();
3539 // convert the pixels to lower precision and upload the texture
3540 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
3542 // after we compute the static lighting we don't need to keep the highpixels array around
3543 if (settings.staticmode)
3545 r_shadow_bouncegrid_state.highpixels = NULL;
3546 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
3547 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
3548 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
3549 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
3550 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
3551 r_shadow_bouncegrid_state.maxsplatpaths = 0;
3555 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
3557 R_Shadow_RenderMode_Reset();
3558 GL_BlendFunc(GL_ONE, GL_ONE);
3559 GL_DepthRange(0, 1);
3560 GL_DepthTest(r_showshadowvolumes.integer < 2);
3561 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
3562 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
3563 GL_CullFace(GL_NONE);
3564 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
3567 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
3569 R_Shadow_RenderMode_Reset();
3570 GL_BlendFunc(GL_ONE, GL_ONE);
3571 GL_DepthRange(0, 1);
3572 GL_DepthTest(r_showlighting.integer < 2);
3573 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
3575 GL_DepthFunc(GL_EQUAL);
3576 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
3577 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
3580 void R_Shadow_RenderMode_End(void)
3582 R_Shadow_RenderMode_Reset();
3583 R_Shadow_RenderMode_ActiveLight(NULL);
3585 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3586 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3589 int bboxedges[12][2] =
3608 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
3610 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
3612 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
3613 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
3614 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
3615 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
3618 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
3619 return true; // invisible
3620 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
3621 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
3622 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
3623 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
3624 r_refdef.stats[r_stat_lights_scissored]++;
3628 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
3631 const float *vertex3f;
3632 const float *normal3f;
3634 float dist, dot, distintensity, shadeintensity, v[3], n[3];
3635 switch (r_shadow_rendermode)
3637 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3638 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3639 if (VectorLength2(diffusecolor) > 0)
3641 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
3643 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3644 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3645 if ((dot = DotProduct(n, v)) < 0)
3647 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3648 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
3651 VectorCopy(ambientcolor, color4f);
3652 if (r_refdef.fogenabled)
3655 f = RSurf_FogVertex(vertex3f);
3656 VectorScale(color4f, f, color4f);
3663 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3665 VectorCopy(ambientcolor, color4f);
3666 if (r_refdef.fogenabled)
3669 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3670 f = RSurf_FogVertex(vertex3f);
3671 VectorScale(color4f + 4*i, f, color4f);
3677 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3678 if (VectorLength2(diffusecolor) > 0)
3680 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
3682 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3683 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3685 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3686 if ((dot = DotProduct(n, v)) < 0)
3688 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3689 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3690 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3691 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3695 color4f[0] = ambientcolor[0] * distintensity;
3696 color4f[1] = ambientcolor[1] * distintensity;
3697 color4f[2] = ambientcolor[2] * distintensity;
3699 if (r_refdef.fogenabled)
3702 f = RSurf_FogVertex(vertex3f);
3703 VectorScale(color4f, f, color4f);
3707 VectorClear(color4f);
3713 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3715 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3716 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3718 color4f[0] = ambientcolor[0] * distintensity;
3719 color4f[1] = ambientcolor[1] * distintensity;
3720 color4f[2] = ambientcolor[2] * distintensity;
3721 if (r_refdef.fogenabled)
3724 f = RSurf_FogVertex(vertex3f);
3725 VectorScale(color4f, f, color4f);
3729 VectorClear(color4f);
3734 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3735 if (VectorLength2(diffusecolor) > 0)
3737 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
3739 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3740 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3742 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3743 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3744 if ((dot = DotProduct(n, v)) < 0)
3746 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3747 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3748 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3749 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3753 color4f[0] = ambientcolor[0] * distintensity;
3754 color4f[1] = ambientcolor[1] * distintensity;
3755 color4f[2] = ambientcolor[2] * distintensity;
3757 if (r_refdef.fogenabled)
3760 f = RSurf_FogVertex(vertex3f);
3761 VectorScale(color4f, f, color4f);
3765 VectorClear(color4f);
3771 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3773 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3774 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3776 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3777 color4f[0] = ambientcolor[0] * distintensity;
3778 color4f[1] = ambientcolor[1] * distintensity;
3779 color4f[2] = ambientcolor[2] * distintensity;
3780 if (r_refdef.fogenabled)
3783 f = RSurf_FogVertex(vertex3f);
3784 VectorScale(color4f, f, color4f);
3788 VectorClear(color4f);
3798 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3800 // used to display how many times a surface is lit for level design purposes
3801 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3802 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3806 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
3808 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3809 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
3813 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3820 int newnumtriangles;
3824 int maxtriangles = 1024;
3825 int newelements[1024*3];
3826 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3827 for (renders = 0;renders < 4;renders++)
3832 newnumtriangles = 0;
3834 // due to low fillrate on the cards this vertex lighting path is
3835 // designed for, we manually cull all triangles that do not
3836 // contain a lit vertex
3837 // this builds batches of triangles from multiple surfaces and
3838 // renders them at once
3839 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3841 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3843 if (newnumtriangles)
3845 newfirstvertex = min(newfirstvertex, e[0]);
3846 newlastvertex = max(newlastvertex, e[0]);
3850 newfirstvertex = e[0];
3851 newlastvertex = e[0];
3853 newfirstvertex = min(newfirstvertex, e[1]);
3854 newlastvertex = max(newlastvertex, e[1]);
3855 newfirstvertex = min(newfirstvertex, e[2]);
3856 newlastvertex = max(newlastvertex, e[2]);
3862 if (newnumtriangles >= maxtriangles)
3864 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3865 newnumtriangles = 0;
3871 if (newnumtriangles >= 1)
3873 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3876 // if we couldn't find any lit triangles, exit early
3879 // now reduce the intensity for the next overbright pass
3880 // we have to clamp to 0 here incase the drivers have improper
3881 // handling of negative colors
3882 // (some old drivers even have improper handling of >1 color)
3884 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3886 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3888 c[0] = max(0, c[0] - 1);
3889 c[1] = max(0, c[1] - 1);
3890 c[2] = max(0, c[2] - 1);
3902 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
3904 // OpenGL 1.1 path (anything)
3905 float ambientcolorbase[3], diffusecolorbase[3];
3906 float ambientcolorpants[3], diffusecolorpants[3];
3907 float ambientcolorshirt[3], diffusecolorshirt[3];
3908 const float *surfacecolor = rsurface.texture->dlightcolor;
3909 const float *surfacepants = rsurface.colormap_pantscolor;
3910 const float *surfaceshirt = rsurface.colormap_shirtcolor;
3911 rtexture_t *basetexture = rsurface.texture->basetexture;
3912 rtexture_t *pantstexture = rsurface.texture->pantstexture;
3913 rtexture_t *shirttexture = rsurface.texture->shirttexture;
3914 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3915 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3916 ambientscale *= 2 * r_refdef.view.colorscale;
3917 diffusescale *= 2 * r_refdef.view.colorscale;
3918 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3919 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3920 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3921 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3922 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3923 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
3924 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3925 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
3926 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3927 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
3928 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
3929 R_Mesh_TexBind(0, basetexture);
3930 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
3931 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
3932 switch(r_shadow_rendermode)
3934 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3935 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
3936 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3937 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3938 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3940 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3941 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
3942 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
3943 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
3944 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3946 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3947 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
3948 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3949 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3950 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3952 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3957 //R_Mesh_TexBind(0, basetexture);
3958 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
3961 R_Mesh_TexBind(0, pantstexture);
3962 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
3966 R_Mesh_TexBind(0, shirttexture);
3967 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
3971 extern cvar_t gl_lightmaps;
3972 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3974 float ambientscale, diffusescale, specularscale;
3976 float lightcolor[3];
3977 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
3978 ambientscale = rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient;
3979 diffusescale = rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient);
3980 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3981 if (!r_shadow_usenormalmap.integer)
3983 ambientscale += 1.0f * diffusescale;
3987 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
3989 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
3992 VectorNegate(lightcolor, lightcolor);
3993 GL_BlendEquationSubtract(true);
3995 RSurf_SetupDepthAndCulling();
3996 switch (r_shadow_rendermode)
3998 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3999 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
4000 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
4002 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
4003 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
4005 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
4006 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
4007 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
4008 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
4009 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
4012 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
4016 GL_BlendEquationSubtract(false);
4019 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)
4021 matrix4x4_t tempmatrix = *matrix;
4022 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
4024 // if this light has been compiled before, free the associated data
4025 R_RTLight_Uncompile(rtlight);
4027 // clear it completely to avoid any lingering data
4028 memset(rtlight, 0, sizeof(*rtlight));
4030 // copy the properties
4031 rtlight->matrix_lighttoworld = tempmatrix;
4032 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
4033 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
4034 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
4035 VectorCopy(color, rtlight->color);
4036 rtlight->cubemapname[0] = 0;
4037 if (cubemapname && cubemapname[0])
4038 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
4039 rtlight->shadow = shadow;
4040 rtlight->corona = corona;
4041 rtlight->style = style;
4042 rtlight->isstatic = isstatic;
4043 rtlight->coronasizescale = coronasizescale;
4044 rtlight->ambientscale = ambientscale;
4045 rtlight->diffusescale = diffusescale;
4046 rtlight->specularscale = specularscale;
4047 rtlight->flags = flags;
4049 // compute derived data
4050 //rtlight->cullradius = rtlight->radius;
4051 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
4052 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
4053 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
4054 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
4055 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
4056 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
4057 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
4060 // compiles rtlight geometry
4061 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
4062 void R_RTLight_Compile(rtlight_t *rtlight)
4065 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
4066 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
4067 entity_render_t *ent = r_refdef.scene.worldentity;
4068 dp_model_t *model = r_refdef.scene.worldmodel;
4069 unsigned char *data;
4072 // compile the light
4073 rtlight->compiled = true;
4074 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
4075 rtlight->static_numleafs = 0;
4076 rtlight->static_numleafpvsbytes = 0;
4077 rtlight->static_leaflist = NULL;
4078 rtlight->static_leafpvs = NULL;
4079 rtlight->static_numsurfaces = 0;
4080 rtlight->static_surfacelist = NULL;
4081 rtlight->static_shadowmap_receivers = 0x3F;
4082 rtlight->static_shadowmap_casters = 0x3F;
4083 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
4084 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
4085 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
4086 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
4087 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
4088 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
4090 if (model && model->GetLightInfo)
4092 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
4093 r_shadow_compilingrtlight = rtlight;
4094 R_FrameData_SetMark();
4095 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);
4096 R_FrameData_ReturnToMark();
4097 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
4098 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
4099 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
4100 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
4101 rtlight->static_numsurfaces = numsurfaces;
4102 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
4103 rtlight->static_numleafs = numleafs;
4104 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
4105 rtlight->static_numleafpvsbytes = numleafpvsbytes;
4106 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
4107 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
4108 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
4109 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
4110 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
4111 if (rtlight->static_numsurfaces)
4112 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
4113 if (rtlight->static_numleafs)
4114 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
4115 if (rtlight->static_numleafpvsbytes)
4116 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
4117 if (rtlight->static_numshadowtrispvsbytes)
4118 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
4119 if (rtlight->static_numlighttrispvsbytes)
4120 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
4121 R_FrameData_SetMark();
4122 switch (rtlight->shadowmode)
4124 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4125 if (model->CompileShadowMap && rtlight->shadow)
4126 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
4129 if (model->CompileShadowVolume && rtlight->shadow)
4130 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
4133 R_FrameData_ReturnToMark();
4134 // now we're done compiling the rtlight
4135 r_shadow_compilingrtlight = NULL;
4139 // use smallest available cullradius - box radius or light radius
4140 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
4141 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
4143 shadowzpasstris = 0;
4144 if (rtlight->static_meshchain_shadow_zpass)
4145 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
4146 shadowzpasstris += mesh->numtriangles;
4148 shadowzfailtris = 0;
4149 if (rtlight->static_meshchain_shadow_zfail)
4150 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
4151 shadowzfailtris += mesh->numtriangles;
4154 if (rtlight->static_numlighttrispvsbytes)
4155 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
4156 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
4160 if (rtlight->static_numshadowtrispvsbytes)
4161 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
4162 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
4165 if (developer_extra.integer)
4166 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);
4169 void R_RTLight_Uncompile(rtlight_t *rtlight)
4171 if (rtlight->compiled)
4173 if (rtlight->static_meshchain_shadow_zpass)
4174 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
4175 rtlight->static_meshchain_shadow_zpass = NULL;
4176 if (rtlight->static_meshchain_shadow_zfail)
4177 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
4178 rtlight->static_meshchain_shadow_zfail = NULL;
4179 if (rtlight->static_meshchain_shadow_shadowmap)
4180 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
4181 rtlight->static_meshchain_shadow_shadowmap = NULL;
4182 // these allocations are grouped
4183 if (rtlight->static_surfacelist)
4184 Mem_Free(rtlight->static_surfacelist);
4185 rtlight->static_numleafs = 0;
4186 rtlight->static_numleafpvsbytes = 0;
4187 rtlight->static_leaflist = NULL;
4188 rtlight->static_leafpvs = NULL;
4189 rtlight->static_numsurfaces = 0;
4190 rtlight->static_surfacelist = NULL;
4191 rtlight->static_numshadowtrispvsbytes = 0;
4192 rtlight->static_shadowtrispvs = NULL;
4193 rtlight->static_numlighttrispvsbytes = 0;
4194 rtlight->static_lighttrispvs = NULL;
4195 rtlight->compiled = false;
4199 void R_Shadow_UncompileWorldLights(void)
4203 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4204 for (lightindex = 0;lightindex < range;lightindex++)
4206 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4209 R_RTLight_Uncompile(&light->rtlight);
4213 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
4217 // reset the count of frustum planes
4218 // see rtlight->cached_frustumplanes definition for how much this array
4220 rtlight->cached_numfrustumplanes = 0;
4222 if (r_trippy.integer)
4225 // haven't implemented a culling path for ortho rendering
4226 if (!r_refdef.view.useperspective)
4228 // check if the light is on screen and copy the 4 planes if it is
4229 for (i = 0;i < 4;i++)
4230 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4233 for (i = 0;i < 4;i++)
4234 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4239 // generate a deformed frustum that includes the light origin, this is
4240 // used to cull shadow casting surfaces that can not possibly cast a
4241 // shadow onto the visible light-receiving surfaces, which can be a
4244 // if the light origin is onscreen the result will be 4 planes exactly
4245 // if the light origin is offscreen on only one axis the result will
4246 // be exactly 5 planes (split-side case)
4247 // if the light origin is offscreen on two axes the result will be
4248 // exactly 4 planes (stretched corner case)
4249 for (i = 0;i < 4;i++)
4251 // quickly reject standard frustum planes that put the light
4252 // origin outside the frustum
4253 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4256 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4258 // if all the standard frustum planes were accepted, the light is onscreen
4259 // otherwise we need to generate some more planes below...
4260 if (rtlight->cached_numfrustumplanes < 4)
4262 // at least one of the stock frustum planes failed, so we need to
4263 // create one or two custom planes to enclose the light origin
4264 for (i = 0;i < 4;i++)
4266 // create a plane using the view origin and light origin, and a
4267 // single point from the frustum corner set
4268 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
4269 VectorNormalize(plane.normal);
4270 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
4271 // see if this plane is backwards and flip it if so
4272 for (j = 0;j < 4;j++)
4273 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4277 VectorNegate(plane.normal, plane.normal);
4279 // flipped plane, test again to see if it is now valid
4280 for (j = 0;j < 4;j++)
4281 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4283 // if the plane is still not valid, then it is dividing the
4284 // frustum and has to be rejected
4288 // we have created a valid plane, compute extra info
4289 PlaneClassify(&plane);
4291 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4293 // if we've found 5 frustum planes then we have constructed a
4294 // proper split-side case and do not need to keep searching for
4295 // planes to enclose the light origin
4296 if (rtlight->cached_numfrustumplanes == 5)
4304 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
4306 plane = rtlight->cached_frustumplanes[i];
4307 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));
4312 // now add the light-space box planes if the light box is rotated, as any
4313 // caster outside the oriented light box is irrelevant (even if it passed
4314 // the worldspace light box, which is axial)
4315 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
4317 for (i = 0;i < 6;i++)
4321 v[i >> 1] = (i & 1) ? -1 : 1;
4322 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
4323 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
4324 plane.dist = VectorNormalizeLength(plane.normal);
4325 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
4326 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4332 // add the world-space reduced box planes
4333 for (i = 0;i < 6;i++)
4335 VectorClear(plane.normal);
4336 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
4337 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
4338 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4347 // reduce all plane distances to tightly fit the rtlight cull box, which
4349 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4350 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4351 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4352 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4353 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4354 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4355 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4356 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4357 oldnum = rtlight->cached_numfrustumplanes;
4358 rtlight->cached_numfrustumplanes = 0;
4359 for (j = 0;j < oldnum;j++)
4361 // find the nearest point on the box to this plane
4362 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
4363 for (i = 1;i < 8;i++)
4365 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
4366 if (bestdist > dist)
4369 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);
4370 // if the nearest point is near or behind the plane, we want this
4371 // plane, otherwise the plane is useless as it won't cull anything
4372 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
4374 PlaneClassify(&rtlight->cached_frustumplanes[j]);
4375 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
4382 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
4386 RSurf_ActiveWorldEntity();
4388 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4391 GL_CullFace(GL_NONE);
4392 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
4393 for (;mesh;mesh = mesh->next)
4395 if (!mesh->sidetotals[r_shadow_shadowmapside])
4397 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
4398 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4399 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);
4403 else if (r_refdef.scene.worldentity->model)
4404 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);
4406 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4409 static void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
4411 qboolean zpass = false;
4414 int surfacelistindex;
4415 msurface_t *surface;
4417 // if triangle neighbors are disabled, shadowvolumes are disabled
4418 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
4421 RSurf_ActiveWorldEntity();
4423 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4426 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
4428 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
4429 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
4431 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
4432 for (;mesh;mesh = mesh->next)
4434 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->numtriangles;
4435 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4436 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
4438 // increment stencil if frontface is infront of depthbuffer
4439 GL_CullFace(r_refdef.view.cullface_back);
4440 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
4441 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);
4442 // decrement stencil if backface is infront of depthbuffer
4443 GL_CullFace(r_refdef.view.cullface_front);
4444 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
4446 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
4448 // decrement stencil if backface is behind depthbuffer
4449 GL_CullFace(r_refdef.view.cullface_front);
4450 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
4451 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);
4452 // increment stencil if frontface is behind depthbuffer
4453 GL_CullFace(r_refdef.view.cullface_back);
4454 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
4456 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);
4460 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
4462 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
4463 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
4464 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
4466 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
4467 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
4468 if (CHECKPVSBIT(trispvs, t))
4469 shadowmarklist[numshadowmark++] = t;
4471 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);
4473 else if (numsurfaces)
4475 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);
4478 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4481 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
4483 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
4484 vec_t relativeshadowradius;
4485 RSurf_ActiveModelEntity(ent, false, false, false);
4486 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
4487 // we need to re-init the shader for each entity because the matrix changed
4488 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
4489 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
4490 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
4491 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
4492 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
4493 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
4494 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
4495 switch (r_shadow_rendermode)
4497 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
4498 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4501 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4504 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4507 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
4509 // set up properties for rendering light onto this entity
4510 RSurf_ActiveModelEntity(ent, true, true, false);
4511 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
4512 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4513 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4514 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4517 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
4519 if (!r_refdef.scene.worldmodel->DrawLight)
4522 // set up properties for rendering light onto this entity
4523 RSurf_ActiveWorldEntity();
4524 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
4525 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4526 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4527 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4529 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
4531 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4534 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
4536 dp_model_t *model = ent->model;
4537 if (!model->DrawLight)
4540 R_Shadow_SetupEntityLight(ent);
4542 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
4544 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4547 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
4551 int numleafs, numsurfaces;
4552 int *leaflist, *surfacelist;
4553 unsigned char *leafpvs;
4554 unsigned char *shadowtrispvs;
4555 unsigned char *lighttrispvs;
4556 //unsigned char *surfacesides;
4557 int numlightentities;
4558 int numlightentities_noselfshadow;
4559 int numshadowentities;
4560 int numshadowentities_noselfshadow;
4561 // FIXME: bounds check lightentities and shadowentities, etc.
4562 static entity_render_t *lightentities[MAX_EDICTS];
4563 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
4564 static entity_render_t *shadowentities[MAX_EDICTS];
4565 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
4567 qboolean castshadows;
4569 rtlight->draw = false;
4570 rtlight->cached_numlightentities = 0;
4571 rtlight->cached_numlightentities_noselfshadow = 0;
4572 rtlight->cached_numshadowentities = 0;
4573 rtlight->cached_numshadowentities_noselfshadow = 0;
4574 rtlight->cached_numsurfaces = 0;
4575 rtlight->cached_lightentities = NULL;
4576 rtlight->cached_lightentities_noselfshadow = NULL;
4577 rtlight->cached_shadowentities = NULL;
4578 rtlight->cached_shadowentities_noselfshadow = NULL;
4579 rtlight->cached_shadowtrispvs = NULL;
4580 rtlight->cached_lighttrispvs = NULL;
4581 rtlight->cached_surfacelist = NULL;
4582 rtlight->shadowmapsidesize = 0;
4584 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
4585 // skip lights that are basically invisible (color 0 0 0)
4586 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
4588 // loading is done before visibility checks because loading should happen
4589 // all at once at the start of a level, not when it stalls gameplay.
4590 // (especially important to benchmarks)
4592 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
4594 if (rtlight->compiled)
4595 R_RTLight_Uncompile(rtlight);
4596 R_RTLight_Compile(rtlight);
4600 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
4602 // look up the light style value at this time
4603 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4604 VectorScale(rtlight->color, f, rtlight->currentcolor);
4606 if (rtlight->selected)
4608 f = 2 + sin(realtime * M_PI * 4.0);
4609 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
4613 // if lightstyle is currently off, don't draw the light
4614 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
4617 // skip processing on corona-only lights
4621 // if the light box is offscreen, skip it
4622 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
4625 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
4626 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
4628 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4630 // 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
4631 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
4634 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
4636 // compiled light, world available and can receive realtime lighting
4637 // retrieve leaf information
4638 numleafs = rtlight->static_numleafs;
4639 leaflist = rtlight->static_leaflist;
4640 leafpvs = rtlight->static_leafpvs;
4641 numsurfaces = rtlight->static_numsurfaces;
4642 surfacelist = rtlight->static_surfacelist;
4643 //surfacesides = NULL;
4644 shadowtrispvs = rtlight->static_shadowtrispvs;
4645 lighttrispvs = rtlight->static_lighttrispvs;
4647 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4649 // dynamic light, world available and can receive realtime lighting
4650 // calculate lit surfaces and leafs
4651 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);
4652 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4653 leaflist = r_shadow_buffer_leaflist;
4654 leafpvs = r_shadow_buffer_leafpvs;
4655 surfacelist = r_shadow_buffer_surfacelist;
4656 //surfacesides = r_shadow_buffer_surfacesides;
4657 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4658 lighttrispvs = r_shadow_buffer_lighttrispvs;
4659 // if the reduced leaf bounds are offscreen, skip it
4660 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4671 //surfacesides = NULL;
4672 shadowtrispvs = NULL;
4673 lighttrispvs = NULL;
4675 // check if light is illuminating any visible leafs
4678 for (i = 0; i < numleafs; i++)
4679 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4685 // make a list of lit entities and shadow casting entities
4686 numlightentities = 0;
4687 numlightentities_noselfshadow = 0;
4688 numshadowentities = 0;
4689 numshadowentities_noselfshadow = 0;
4691 // add dynamic entities that are lit by the light
4692 for (i = 0; i < r_refdef.scene.numentities; i++)
4695 entity_render_t *ent = r_refdef.scene.entities[i];
4697 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4699 // skip the object entirely if it is not within the valid
4700 // shadow-casting region (which includes the lit region)
4701 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
4703 if (!(model = ent->model))
4705 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4707 // this entity wants to receive light, is visible, and is
4708 // inside the light box
4709 // TODO: check if the surfaces in the model can receive light
4710 // so now check if it's in a leaf seen by the light
4711 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))
4713 if (ent->flags & RENDER_NOSELFSHADOW)
4714 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
4716 lightentities[numlightentities++] = ent;
4717 // since it is lit, it probably also casts a shadow...
4718 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4719 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4720 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4722 // note: exterior models without the RENDER_NOSELFSHADOW
4723 // flag still create a RENDER_NOSELFSHADOW shadow but
4724 // are lit normally, this means that they are
4725 // self-shadowing but do not shadow other
4726 // RENDER_NOSELFSHADOW entities such as the gun
4727 // (very weird, but keeps the player shadow off the gun)
4728 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4729 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4731 shadowentities[numshadowentities++] = ent;
4734 else if (ent->flags & RENDER_SHADOW)
4736 // this entity is not receiving light, but may still need to
4738 // TODO: check if the surfaces in the model can cast shadow
4739 // now check if it is in a leaf seen by the light
4740 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))
4742 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4743 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4744 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4746 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4747 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4749 shadowentities[numshadowentities++] = ent;
4754 // return if there's nothing at all to light
4755 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4758 // count this light in the r_speeds
4759 r_refdef.stats[r_stat_lights]++;
4761 // flag it as worth drawing later
4762 rtlight->draw = true;
4764 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
4765 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4767 numshadowentities = numshadowentities_noselfshadow = 0;
4768 rtlight->castshadows = castshadows;
4770 // cache all the animated entities that cast a shadow but are not visible
4771 for (i = 0; i < numshadowentities; i++)
4772 R_AnimCache_GetEntity(shadowentities[i], false, false);
4773 for (i = 0; i < numshadowentities_noselfshadow; i++)
4774 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4776 // 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)
4777 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
4779 for (i = 0; i < numshadowentities_noselfshadow; i++)
4780 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
4781 numshadowentities_noselfshadow = 0;
4784 // we can convert noselfshadow to regular if there are no casters of that type
4785 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
4787 for (i = 0; i < numlightentities_noselfshadow; i++)
4788 lightentities[numlightentities++] = lightentities_noselfshadow[i];
4789 numlightentities_noselfshadow = 0;
4792 // allocate some temporary memory for rendering this light later in the frame
4793 // reusable buffers need to be copied, static data can be used as-is
4794 rtlight->cached_numlightentities = numlightentities;
4795 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
4796 rtlight->cached_numshadowentities = numshadowentities;
4797 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4798 rtlight->cached_numsurfaces = numsurfaces;
4799 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4800 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4801 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4802 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4803 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4805 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4806 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4807 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4808 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4809 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4813 // compiled light data
4814 rtlight->cached_shadowtrispvs = shadowtrispvs;
4815 rtlight->cached_lighttrispvs = lighttrispvs;
4816 rtlight->cached_surfacelist = surfacelist;
4819 if (R_Shadow_ShadowMappingEnabled())
4821 // figure out the shadowmapping parameters for this light
4822 vec3_t nearestpoint;
4825 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4826 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4827 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4828 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4829 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
4830 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4831 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4832 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4833 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
4837 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
4841 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4842 int numlightentities;
4843 int numlightentities_noselfshadow;
4844 int numshadowentities;
4845 int numshadowentities_noselfshadow;
4846 entity_render_t **lightentities;
4847 entity_render_t **lightentities_noselfshadow;
4848 entity_render_t **shadowentities;
4849 entity_render_t **shadowentities_noselfshadow;
4851 static unsigned char entitysides[MAX_EDICTS];
4852 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4858 matrix4x4_t radiustolight;
4860 // check if we cached this light this frame (meaning it is worth drawing)
4861 if (!rtlight->draw || !rtlight->castshadows)
4864 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
4865 if (rtlight->shadowmapatlassidesize == 0)
4867 rtlight->castshadows = false;
4871 // set up a scissor rectangle for this light
4872 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4875 // don't let sound skip if going slow
4876 if (r_refdef.scene.extraupdate)
4879 numlightentities = rtlight->cached_numlightentities;
4880 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4881 numshadowentities = rtlight->cached_numshadowentities;
4882 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4883 numsurfaces = rtlight->cached_numsurfaces;
4884 lightentities = rtlight->cached_lightentities;
4885 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4886 shadowentities = rtlight->cached_shadowentities;
4887 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4888 shadowtrispvs = rtlight->cached_shadowtrispvs;
4889 lighttrispvs = rtlight->cached_lighttrispvs;
4890 surfacelist = rtlight->cached_surfacelist;
4892 // make this the active rtlight for rendering purposes
4893 R_Shadow_RenderMode_ActiveLight(rtlight);
4895 radiustolight = rtlight->matrix_worldtolight;
4896 Matrix4x4_Abs(&radiustolight);
4898 size = rtlight->shadowmapatlassidesize;
4899 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4901 surfacesides = NULL;
4906 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4908 castermask = rtlight->static_shadowmap_casters;
4909 receivermask = rtlight->static_shadowmap_receivers;
4913 surfacesides = r_shadow_buffer_surfacesides;
4914 for (i = 0; i < numsurfaces; i++)
4916 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4917 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4918 castermask |= surfacesides[i];
4919 receivermask |= surfacesides[i];
4924 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
4925 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4926 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
4927 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4929 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4933 for (i = 0; i < numshadowentities; i++)
4934 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4935 for (i = 0; i < numshadowentities_noselfshadow; i++)
4936 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4939 // there is no need to render shadows for sides that have no receivers...
4940 castermask &= receivermask;
4942 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
4944 // render shadow casters into shadowmaps for this light
4945 for (side = 0; side < 6; side++)
4947 int bit = 1 << side;
4948 if (castermask & bit)
4950 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
4952 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4953 for (i = 0; i < numshadowentities; i++)
4954 if (entitysides[i] & bit)
4955 R_Shadow_DrawEntityShadow(shadowentities[i]);
4956 for (i = 0; i < numshadowentities_noselfshadow; i++)
4957 if (entitysides_noselfshadow[i] & bit)
4958 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4961 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
4962 if (numshadowentities_noselfshadow)
4964 for (side = 0; side < 6; side++)
4966 int bit = 1 << side;
4967 if (castermask & bit)
4969 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
4971 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4972 for (i = 0; i < numshadowentities; i++)
4973 if (entitysides[i] & bit)
4974 R_Shadow_DrawEntityShadow(shadowentities[i]);
4980 static void R_Shadow_DrawLight(rtlight_t *rtlight)
4984 unsigned char *shadowtrispvs, *lighttrispvs;
4985 int numlightentities;
4986 int numlightentities_noselfshadow;
4987 int numshadowentities;
4988 int numshadowentities_noselfshadow;
4989 entity_render_t **lightentities;
4990 entity_render_t **lightentities_noselfshadow;
4991 entity_render_t **shadowentities;
4992 entity_render_t **shadowentities_noselfshadow;
4994 qboolean castshadows;
4996 // check if we cached this light this frame (meaning it is worth drawing)
5000 // set up a scissor rectangle for this light
5001 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
5004 // don't let sound skip if going slow
5005 if (r_refdef.scene.extraupdate)
5008 numlightentities = rtlight->cached_numlightentities;
5009 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
5010 numshadowentities = rtlight->cached_numshadowentities;
5011 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
5012 numsurfaces = rtlight->cached_numsurfaces;
5013 lightentities = rtlight->cached_lightentities;
5014 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
5015 shadowentities = rtlight->cached_shadowentities;
5016 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
5017 shadowtrispvs = rtlight->cached_shadowtrispvs;
5018 lighttrispvs = rtlight->cached_lighttrispvs;
5019 surfacelist = rtlight->cached_surfacelist;
5020 castshadows = rtlight->castshadows;
5022 // make this the active rtlight for rendering purposes
5023 R_Shadow_RenderMode_ActiveLight(rtlight);
5025 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
5027 // optionally draw visible shape of the shadow volumes
5028 // for performance analysis by level designers
5029 R_Shadow_RenderMode_VisibleShadowVolumes();
5031 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
5032 for (i = 0;i < numshadowentities;i++)
5033 R_Shadow_DrawEntityShadow(shadowentities[i]);
5034 for (i = 0;i < numshadowentities_noselfshadow;i++)
5035 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5036 R_Shadow_RenderMode_VisibleLighting(false, false);
5039 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
5041 // optionally draw the illuminated areas
5042 // for performance analysis by level designers
5043 R_Shadow_RenderMode_VisibleLighting(false, false);
5045 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5046 for (i = 0;i < numlightentities;i++)
5047 R_Shadow_DrawEntityLight(lightentities[i]);
5048 for (i = 0;i < numlightentities_noselfshadow;i++)
5049 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5052 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
5056 float shadowmapoffsetnoselfshadow = 0;
5057 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
5058 Matrix4x4_Abs(&radiustolight);
5060 size = rtlight->shadowmapatlassidesize;
5061 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
5063 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
5065 if (rtlight->cached_numshadowentities_noselfshadow)
5066 shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
5068 // render lighting using the depth texture as shadowmap
5069 // draw lighting in the unmasked areas
5070 if (numsurfaces + numlightentities)
5072 R_Shadow_RenderMode_Lighting(false, false, true, false);
5073 // draw lighting in the unmasked areas
5075 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5076 for (i = 0; i < numlightentities; i++)
5077 R_Shadow_DrawEntityLight(lightentities[i]);
5079 // offset to the noselfshadow part of the atlas and draw those too
5080 if (numlightentities_noselfshadow)
5082 R_Shadow_RenderMode_Lighting(false, false, true, true);
5083 for (i = 0; i < numlightentities_noselfshadow; i++)
5084 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5087 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5088 if (r_shadow_usingdeferredprepass)
5089 R_Shadow_RenderMode_DrawDeferredLight(true);
5091 else if (castshadows && vid.stencil)
5093 // draw stencil shadow volumes to mask off pixels that are in shadow
5094 // so that they won't receive lighting
5095 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
5096 R_Shadow_ClearStencil();
5099 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
5100 for (i = 0;i < numshadowentities;i++)
5101 R_Shadow_DrawEntityShadow(shadowentities[i]);
5103 // draw lighting in the unmasked areas
5104 R_Shadow_RenderMode_Lighting(true, false, false, false);
5105 for (i = 0;i < numlightentities_noselfshadow;i++)
5106 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5108 for (i = 0;i < numshadowentities_noselfshadow;i++)
5109 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5111 // draw lighting in the unmasked areas
5112 R_Shadow_RenderMode_Lighting(true, false, false, false);
5114 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5115 for (i = 0;i < numlightentities;i++)
5116 R_Shadow_DrawEntityLight(lightentities[i]);
5118 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5119 if (r_shadow_usingdeferredprepass)
5120 R_Shadow_RenderMode_DrawDeferredLight(false);
5124 // draw lighting in the unmasked areas
5125 R_Shadow_RenderMode_Lighting(false, false, false, false);
5127 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5128 for (i = 0;i < numlightentities;i++)
5129 R_Shadow_DrawEntityLight(lightentities[i]);
5130 for (i = 0;i < numlightentities_noselfshadow;i++)
5131 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5133 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5134 if (r_shadow_usingdeferredprepass)
5135 R_Shadow_RenderMode_DrawDeferredLight(false);
5139 static void R_Shadow_FreeDeferred(void)
5141 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
5142 r_shadow_prepassgeometryfbo = 0;
5144 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
5145 r_shadow_prepasslightingdiffusespecularfbo = 0;
5147 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
5148 r_shadow_prepasslightingdiffusefbo = 0;
5150 if (r_shadow_prepassgeometrydepthbuffer)
5151 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
5152 r_shadow_prepassgeometrydepthbuffer = NULL;
5154 if (r_shadow_prepassgeometrynormalmaptexture)
5155 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
5156 r_shadow_prepassgeometrynormalmaptexture = NULL;
5158 if (r_shadow_prepasslightingdiffusetexture)
5159 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
5160 r_shadow_prepasslightingdiffusetexture = NULL;
5162 if (r_shadow_prepasslightingspeculartexture)
5163 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
5164 r_shadow_prepasslightingspeculartexture = NULL;
5167 void R_Shadow_DrawPrepass(void)
5171 entity_render_t *ent;
5172 float clearcolor[4];
5174 R_Mesh_ResetTextureState();
5176 GL_ColorMask(1,1,1,1);
5177 GL_BlendFunc(GL_ONE, GL_ZERO);
5180 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5181 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
5182 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
5183 if (r_timereport_active)
5184 R_TimeReport("prepasscleargeom");
5186 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
5187 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
5188 if (r_timereport_active)
5189 R_TimeReport("prepassworld");
5191 for (i = 0;i < r_refdef.scene.numentities;i++)
5193 if (!r_refdef.viewcache.entityvisible[i])
5195 ent = r_refdef.scene.entities[i];
5196 if (ent->model && ent->model->DrawPrepass != NULL)
5197 ent->model->DrawPrepass(ent);
5200 if (r_timereport_active)
5201 R_TimeReport("prepassmodels");
5203 GL_DepthMask(false);
5204 GL_ColorMask(1,1,1,1);
5207 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5208 Vector4Set(clearcolor, 0, 0, 0, 0);
5209 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
5210 if (r_timereport_active)
5211 R_TimeReport("prepassclearlit");
5213 R_Shadow_RenderMode_Begin();
5215 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5216 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5218 R_Shadow_RenderMode_End();
5220 if (r_timereport_active)
5221 R_TimeReport("prepasslights");
5224 #define MAX_SCENELIGHTS 65536
5225 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
5227 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
5229 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
5231 r_shadow_scenemaxlights *= 2;
5232 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
5233 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
5235 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
5239 void R_Shadow_DrawLightSprites(void);
5240 void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
5249 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
5250 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
5251 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
5253 if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
5254 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
5255 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
5256 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
5257 r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) ||
5258 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
5259 r_shadow_shadowmapborder != shadowmapborder ||
5260 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
5261 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
5262 R_Shadow_FreeShadowMaps();
5264 r_shadow_fb_fbo = fbo;
5265 r_shadow_fb_depthtexture = depthtexture;
5266 r_shadow_fb_colortexture = colortexture;
5268 r_shadow_usingshadowmaportho = false;
5270 switch (vid.renderpath)
5272 case RENDERPATH_GL20:
5273 case RENDERPATH_D3D9:
5274 case RENDERPATH_D3D10:
5275 case RENDERPATH_D3D11:
5276 case RENDERPATH_SOFT:
5278 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
5280 r_shadow_usingdeferredprepass = false;
5281 if (r_shadow_prepass_width)
5282 R_Shadow_FreeDeferred();
5283 r_shadow_prepass_width = r_shadow_prepass_height = 0;
5287 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
5289 R_Shadow_FreeDeferred();
5291 r_shadow_usingdeferredprepass = true;
5292 r_shadow_prepass_width = vid.width;
5293 r_shadow_prepass_height = vid.height;
5294 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
5295 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);
5296 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);
5297 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);
5299 // set up the geometry pass fbo (depth + normalmap)
5300 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5301 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5302 // render depth into a renderbuffer and other important properties into the normalmap texture
5304 // set up the lighting pass fbo (diffuse + specular)
5305 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5306 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5307 // render diffuse into one texture and specular into another,
5308 // with depth and normalmap bound as textures,
5309 // with depth bound as attachment as well
5311 // set up the lighting pass fbo (diffuse)
5312 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5313 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5314 // render diffuse into one texture,
5315 // with depth and normalmap bound as textures,
5316 // with depth bound as attachment as well
5320 case RENDERPATH_GL11:
5321 case RENDERPATH_GL13:
5322 case RENDERPATH_GLES1:
5323 case RENDERPATH_GLES2:
5324 r_shadow_usingdeferredprepass = false;
5328 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);
5330 r_shadow_scenenumlights = 0;
5331 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5332 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5333 for (lightindex = 0; lightindex < range; lightindex++)
5335 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5336 if (light && (light->flags & flag))
5338 R_Shadow_PrepareLight(&light->rtlight);
5339 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5342 if (r_refdef.scene.rtdlight)
5344 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5346 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
5347 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
5350 else if (gl_flashblend.integer)
5352 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5354 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
5355 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
5356 VectorScale(rtlight->color, f, rtlight->currentcolor);
5360 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
5361 if (r_shadow_debuglight.integer >= 0)
5363 r_shadow_scenenumlights = 0;
5364 lightindex = r_shadow_debuglight.integer;
5365 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5368 R_Shadow_PrepareLight(&light->rtlight);
5369 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5373 // if we're doing shadowmaps we need to prepare the atlas layout now
5374 if (R_Shadow_ShadowMappingEnabled())
5378 // allocate shadowmaps in the atlas now
5379 // 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...
5380 for (lod = 0; lod < 16; lod++)
5382 int packing_success = 0;
5383 int packing_failure = 0;
5384 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
5385 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
5386 if (r_shadow_shadowmapatlas_modelshadows_size)
5387 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);
5388 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5390 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
5391 int size = rtlight->shadowmapsidesize >> lod;
5393 if (!rtlight->castshadows)
5395 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
5398 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
5399 if (rtlight->cached_numshadowentities_noselfshadow)
5401 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
5403 rtlight->shadowmapatlassidesize = size;
5408 // note down that we failed to pack this one, it will have to disable shadows
5409 rtlight->shadowmapatlassidesize = 0;
5413 // generally everything fits and we stop here on the first iteration
5414 if (packing_failure == 0)
5419 if (r_editlights.integer)
5420 R_Shadow_DrawLightSprites();
5423 void R_Shadow_DrawShadowMaps(void)
5425 R_Shadow_RenderMode_Begin();
5426 R_Shadow_RenderMode_ActiveLight(NULL);
5428 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
5429 R_Shadow_ClearShadowMapTexture();
5431 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
5432 if (r_shadow_shadowmapatlas_modelshadows_size)
5434 R_Shadow_DrawModelShadowMaps();
5435 // don't let sound skip if going slow
5436 if (r_refdef.scene.extraupdate)
5440 if (R_Shadow_ShadowMappingEnabled())
5443 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5444 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
5447 R_Shadow_RenderMode_End();
5450 void R_Shadow_DrawLights(void)
5454 R_Shadow_RenderMode_Begin();
5456 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5457 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5459 R_Shadow_RenderMode_End();
5462 #define MAX_MODELSHADOWS 1024
5463 static int r_shadow_nummodelshadows;
5464 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
5466 void R_Shadow_PrepareModelShadows(void)
5469 float scale, size, radius, dot1, dot2;
5470 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5471 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
5472 entity_render_t *ent;
5474 r_shadow_nummodelshadows = 0;
5475 r_shadow_shadowmapatlas_modelshadows_size = 0;
5477 if (!r_refdef.scene.numentities || r_refdef.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
5480 switch (r_shadow_shadowmode)
5482 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
5483 if (r_shadows.integer >= 2)
5486 case R_SHADOW_SHADOWMODE_STENCIL:
5489 for (i = 0; i < r_refdef.scene.numentities; i++)
5491 ent = r_refdef.scene.entities[i];
5492 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5494 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5496 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5497 R_AnimCache_GetEntity(ent, false, false);
5505 size = 2 * r_shadow_shadowmapmaxsize;
5506 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
5507 radius = 0.5f * size / scale;
5509 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5510 VectorCopy(prvmshadowdir, shadowdir);
5511 VectorNormalize(shadowdir);
5512 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5513 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5514 if (fabs(dot1) <= fabs(dot2))
5515 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5517 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5518 VectorNormalize(shadowforward);
5519 CrossProduct(shadowdir, shadowforward, shadowright);
5520 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5521 VectorCopy(prvmshadowfocus, shadowfocus);
5522 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5523 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5524 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5525 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5526 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5528 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5530 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5531 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5532 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5533 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5534 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5535 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5537 for (i = 0; i < r_refdef.scene.numentities; i++)
5539 ent = r_refdef.scene.entities[i];
5540 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
5542 // cast shadows from anything of the map (submodels are optional)
5543 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5545 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5547 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5548 R_AnimCache_GetEntity(ent, false, false);
5552 if (r_shadow_nummodelshadows)
5554 r_shadow_shadowmapatlas_modelshadows_x = 0;
5555 r_shadow_shadowmapatlas_modelshadows_y = 0;
5556 r_shadow_shadowmapatlas_modelshadows_size = size;
5560 static void R_Shadow_DrawModelShadowMaps(void)
5563 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
5564 entity_render_t *ent;
5565 vec3_t relativelightorigin;
5566 vec3_t relativelightdirection, relativeforward, relativeright;
5567 vec3_t relativeshadowmins, relativeshadowmaxs;
5568 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
5569 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5571 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
5572 r_viewport_t viewport;
5574 size = r_shadow_shadowmapatlas_modelshadows_size;
5575 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
5576 radius = 0.5f / scale;
5577 nearclip = -r_shadows_throwdistance.value;
5578 farclip = r_shadows_throwdistance.value;
5579 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);
5581 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
5582 r_shadow_modelshadowmap_parameters[0] = size;
5583 r_shadow_modelshadowmap_parameters[1] = size;
5584 r_shadow_modelshadowmap_parameters[2] = 1.0;
5585 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
5586 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
5587 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
5588 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
5589 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
5590 r_shadow_usingshadowmaportho = true;
5592 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5593 VectorCopy(prvmshadowdir, shadowdir);
5594 VectorNormalize(shadowdir);
5595 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5596 VectorCopy(prvmshadowfocus, shadowfocus);
5597 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5598 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5599 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5600 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5601 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5602 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5603 if (fabs(dot1) <= fabs(dot2))
5604 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5606 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5607 VectorNormalize(shadowforward);
5608 VectorM(scale, shadowforward, &m[0]);
5609 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5611 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
5612 CrossProduct(shadowdir, shadowforward, shadowright);
5613 VectorM(scale, shadowright, &m[4]);
5614 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
5615 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
5616 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
5617 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
5618 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
5619 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);
5620 R_SetViewport(&viewport);
5622 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5624 // render into a slightly restricted region so that the borders of the
5625 // shadowmap area fade away, rather than streaking across everything
5626 // outside the usable area
5627 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
5629 for (i = 0;i < r_shadow_nummodelshadows;i++)
5631 ent = r_shadow_modelshadows[i];
5632 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5633 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
5634 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5635 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
5636 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
5637 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5638 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5639 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5640 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5641 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5642 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5643 RSurf_ActiveModelEntity(ent, false, false, false);
5644 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
5645 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5651 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
5653 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
5655 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
5656 Cvar_SetValueQuick(&r_test, 0);
5661 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
5662 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
5663 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
5664 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
5665 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
5666 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
5668 switch (vid.renderpath)
5670 case RENDERPATH_GL11:
5671 case RENDERPATH_GL13:
5672 case RENDERPATH_GL20:
5673 case RENDERPATH_SOFT:
5674 case RENDERPATH_GLES1:
5675 case RENDERPATH_GLES2:
5677 case RENDERPATH_D3D9:
5678 case RENDERPATH_D3D10:
5679 case RENDERPATH_D3D11:
5680 #ifdef MATRIX4x4_OPENGLORIENTATION
5681 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5682 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
5683 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
5684 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
5686 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5687 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
5688 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
5689 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
5695 void R_Shadow_DrawModelShadows(void)
5698 float relativethrowdistance;
5699 entity_render_t *ent;
5700 vec3_t relativelightorigin;
5701 vec3_t relativelightdirection;
5702 vec3_t relativeshadowmins, relativeshadowmaxs;
5703 vec3_t tmp, shadowdir;
5704 prvm_vec3_t prvmshadowdir;
5706 if (!r_shadow_nummodelshadows || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
5709 R_ResetViewRendering3D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5710 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
5711 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5712 R_Shadow_RenderMode_Begin();
5713 R_Shadow_RenderMode_ActiveLight(NULL);
5714 r_shadow_lightscissor[0] = r_refdef.view.x;
5715 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
5716 r_shadow_lightscissor[2] = r_refdef.view.width;
5717 r_shadow_lightscissor[3] = r_refdef.view.height;
5718 R_Shadow_RenderMode_StencilShadowVolumes(false);
5721 if (r_shadows.integer == 2)
5723 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5724 VectorCopy(prvmshadowdir, shadowdir);
5725 VectorNormalize(shadowdir);
5728 R_Shadow_ClearStencil();
5730 for (i = 0;i < r_shadow_nummodelshadows;i++)
5732 ent = r_shadow_modelshadows[i];
5734 // cast shadows from anything of the map (submodels are optional)
5735 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5736 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
5737 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
5738 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
5739 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5742 if(ent->entitynumber != 0)
5744 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
5746 // FIXME handle this
5747 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5751 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
5752 int entnum, entnum2, recursion;
5753 entnum = entnum2 = ent->entitynumber;
5754 for(recursion = 32; recursion > 0; --recursion)
5756 entnum2 = cl.entities[entnum].state_current.tagentity;
5757 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
5762 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
5764 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
5765 // transform into modelspace of OUR entity
5766 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
5767 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
5770 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5774 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5777 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
5778 RSurf_ActiveModelEntity(ent, false, false, false);
5779 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
5780 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5783 // not really the right mode, but this will disable any silly stencil features
5784 R_Shadow_RenderMode_End();
5786 // set up ortho view for rendering this pass
5787 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5788 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5789 //GL_ScissorTest(true);
5790 //R_EntityMatrix(&identitymatrix);
5791 //R_Mesh_ResetTextureState();
5792 R_ResetViewRendering2D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5794 // set up a darkening blend on shadowed areas
5795 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5796 //GL_DepthRange(0, 1);
5797 //GL_DepthTest(false);
5798 //GL_DepthMask(false);
5799 //GL_PolygonOffset(0, 0);CHECKGLERROR
5800 GL_Color(0, 0, 0, r_shadows_darken.value);
5801 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5802 //GL_DepthFunc(GL_ALWAYS);
5803 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5805 // apply the blend to the shadowed areas
5806 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5807 R_SetupShader_Generic_NoTexture(false, true);
5808 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5810 // restore the viewport
5811 R_SetViewport(&r_refdef.view.viewport);
5813 // restore other state to normal
5814 //R_Shadow_RenderMode_End();
5817 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5820 vec3_t centerorigin;
5821 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5824 // if it's too close, skip it
5825 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5827 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5830 if (usequery && r_numqueries + 2 <= r_maxqueries)
5832 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5833 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5834 // 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
5835 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5837 switch(vid.renderpath)
5839 case RENDERPATH_GL11:
5840 case RENDERPATH_GL13:
5841 case RENDERPATH_GL20:
5842 case RENDERPATH_GLES1:
5843 case RENDERPATH_GLES2:
5844 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5846 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5847 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5848 GL_DepthFunc(GL_ALWAYS);
5849 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5850 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5851 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5852 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5853 GL_DepthFunc(GL_LEQUAL);
5854 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5855 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5856 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5857 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5858 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5862 case RENDERPATH_D3D9:
5863 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5865 case RENDERPATH_D3D10:
5866 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5868 case RENDERPATH_D3D11:
5869 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5871 case RENDERPATH_SOFT:
5872 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5876 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5879 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5881 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5884 unsigned int occlude = 0;
5885 GLint allpixels = 0, visiblepixels = 0;
5887 // now we have to check the query result
5888 if (rtlight->corona_queryindex_visiblepixels)
5890 switch(vid.renderpath)
5892 case RENDERPATH_GL11:
5893 case RENDERPATH_GL13:
5894 case RENDERPATH_GL20:
5895 case RENDERPATH_GLES1:
5896 case RENDERPATH_GLES2:
5897 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5899 // See if we can use the GPU-side method to prevent implicit sync
5900 if (vid.support.arb_query_buffer_object) {
5901 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
5902 if (!r_shadow_occlusion_buf) {
5903 qglGenBuffersARB(1, &r_shadow_occlusion_buf);
5904 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5905 qglBufferDataARB(GL_QUERY_BUFFER_ARB, 8, NULL, GL_DYNAMIC_COPY);
5907 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5909 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(0));
5910 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4));
5911 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
5912 occlude = MATERIALFLAG_OCCLUDE;
5914 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5915 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5916 if (visiblepixels < 1 || allpixels < 1)
5918 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5920 cscale *= rtlight->corona_visibility;
5926 case RENDERPATH_D3D9:
5927 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5929 case RENDERPATH_D3D10:
5930 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5932 case RENDERPATH_D3D11:
5933 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5935 case RENDERPATH_SOFT:
5936 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5944 // FIXME: these traces should scan all render entities instead of cl.world
5945 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
5948 VectorScale(rtlight->currentcolor, cscale, color);
5949 if (VectorLength(color) > (1.0f / 256.0f))
5952 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
5955 VectorNegate(color, color);
5956 GL_BlendEquationSubtract(true);
5958 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5959 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);
5960 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
5962 GL_BlendEquationSubtract(false);
5966 void R_Shadow_DrawCoronas(void)
5969 qboolean usequery = false;
5974 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
5976 if (r_fb.water.renderingscene)
5978 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5979 R_EntityMatrix(&identitymatrix);
5981 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5983 // check occlusion of coronas
5984 // use GL_ARB_occlusion_query if available
5985 // otherwise use raytraces
5987 switch (vid.renderpath)
5989 case RENDERPATH_GL11:
5990 case RENDERPATH_GL13:
5991 case RENDERPATH_GL20:
5992 case RENDERPATH_GLES1:
5993 case RENDERPATH_GLES2:
5994 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
5995 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5998 GL_ColorMask(0,0,0,0);
5999 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
6000 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
6003 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
6004 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
6006 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
6009 RSurf_ActiveWorldEntity();
6010 GL_BlendFunc(GL_ONE, GL_ZERO);
6011 GL_CullFace(GL_NONE);
6012 GL_DepthMask(false);
6013 GL_DepthRange(0, 1);
6014 GL_PolygonOffset(0, 0);
6016 R_Mesh_ResetTextureState();
6017 R_SetupShader_Generic_NoTexture(false, false);
6021 case RENDERPATH_D3D9:
6023 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6025 case RENDERPATH_D3D10:
6026 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6028 case RENDERPATH_D3D11:
6029 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6031 case RENDERPATH_SOFT:
6033 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6036 for (lightindex = 0;lightindex < range;lightindex++)
6038 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6041 rtlight = &light->rtlight;
6042 rtlight->corona_visibility = 0;
6043 rtlight->corona_queryindex_visiblepixels = 0;
6044 rtlight->corona_queryindex_allpixels = 0;
6045 if (!(rtlight->flags & flag))
6047 if (rtlight->corona <= 0)
6049 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
6051 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6053 for (i = 0;i < r_refdef.scene.numlights;i++)
6055 rtlight = r_refdef.scene.lights[i];
6056 rtlight->corona_visibility = 0;
6057 rtlight->corona_queryindex_visiblepixels = 0;
6058 rtlight->corona_queryindex_allpixels = 0;
6059 if (!(rtlight->flags & flag))
6061 if (rtlight->corona <= 0)
6063 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6066 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
6068 // now draw the coronas using the query data for intensity info
6069 for (lightindex = 0;lightindex < range;lightindex++)
6071 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6074 rtlight = &light->rtlight;
6075 if (rtlight->corona_visibility <= 0)
6077 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6079 for (i = 0;i < r_refdef.scene.numlights;i++)
6081 rtlight = r_refdef.scene.lights[i];
6082 if (rtlight->corona_visibility <= 0)
6084 if (gl_flashblend.integer)
6085 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
6087 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6093 static dlight_t *R_Shadow_NewWorldLight(void)
6095 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
6098 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)
6102 // 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
6104 // validate parameters
6108 // copy to light properties
6109 VectorCopy(origin, light->origin);
6110 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
6111 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
6112 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
6114 light->color[0] = max(color[0], 0);
6115 light->color[1] = max(color[1], 0);
6116 light->color[2] = max(color[2], 0);
6118 light->color[0] = color[0];
6119 light->color[1] = color[1];
6120 light->color[2] = color[2];
6121 light->radius = max(radius, 0);
6122 light->style = style;
6123 light->shadow = shadowenable;
6124 light->corona = corona;
6125 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
6126 light->coronasizescale = coronasizescale;
6127 light->ambientscale = ambientscale;
6128 light->diffusescale = diffusescale;
6129 light->specularscale = specularscale;
6130 light->flags = flags;
6132 // update renderable light data
6133 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
6134 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);
6137 static void R_Shadow_FreeWorldLight(dlight_t *light)
6139 if (r_shadow_selectedlight == light)
6140 r_shadow_selectedlight = NULL;
6141 R_RTLight_Uncompile(&light->rtlight);
6142 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
6145 void R_Shadow_ClearWorldLights(void)
6149 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6150 for (lightindex = 0;lightindex < range;lightindex++)
6152 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6154 R_Shadow_FreeWorldLight(light);
6156 r_shadow_selectedlight = NULL;
6159 static void R_Shadow_SelectLight(dlight_t *light)
6161 if (r_shadow_selectedlight)
6162 r_shadow_selectedlight->selected = false;
6163 r_shadow_selectedlight = light;
6164 if (r_shadow_selectedlight)
6165 r_shadow_selectedlight->selected = true;
6168 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6170 // this is never batched (there can be only one)
6172 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
6173 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6174 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6177 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6182 skinframe_t *skinframe;
6185 // this is never batched (due to the ent parameter changing every time)
6186 // so numsurfaces == 1 and surfacelist[0] == lightnumber
6187 const dlight_t *light = (dlight_t *)ent;
6190 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
6193 VectorScale(light->color, intensity, spritecolor);
6194 if (VectorLength(spritecolor) < 0.1732f)
6195 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
6196 if (VectorLength(spritecolor) > 1.0f)
6197 VectorNormalize(spritecolor);
6199 // draw light sprite
6200 if (light->cubemapname[0] && !light->shadow)
6201 skinframe = r_editlights_sprcubemapnoshadowlight;
6202 else if (light->cubemapname[0])
6203 skinframe = r_editlights_sprcubemaplight;
6204 else if (!light->shadow)
6205 skinframe = r_editlights_sprnoshadowlight;
6207 skinframe = r_editlights_sprlight;
6209 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);
6210 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6212 // draw selection sprite if light is selected
6213 if (light->selected)
6215 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6216 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6217 // VorteX todo: add normalmode/realtime mode light overlay sprites?
6221 void R_Shadow_DrawLightSprites(void)
6225 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6226 for (lightindex = 0;lightindex < range;lightindex++)
6228 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6230 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
6232 if (!r_editlights_lockcursor)
6233 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
6236 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
6241 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6242 if (lightindex >= range)
6244 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6247 rtlight = &light->rtlight;
6248 //if (!(rtlight->flags & flag))
6250 VectorCopy(rtlight->shadoworigin, origin);
6251 *radius = rtlight->radius;
6252 VectorCopy(rtlight->color, color);
6256 static void R_Shadow_SelectLightInView(void)
6258 float bestrating, rating, temp[3];
6262 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6266 if (r_editlights_lockcursor)
6268 for (lightindex = 0;lightindex < range;lightindex++)
6270 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6273 VectorSubtract(light->origin, r_refdef.view.origin, temp);
6274 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
6277 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
6278 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1.0f)
6280 bestrating = rating;
6285 R_Shadow_SelectLight(best);
6288 void R_Shadow_LoadWorldLights(void)
6290 int n, a, style, shadow, flags;
6291 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
6292 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
6293 if (cl.worldmodel == NULL)
6295 Con_Print("No map loaded.\n");
6298 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6299 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6309 for (;COM_Parse(t, true) && strcmp(
6310 if (COM_Parse(t, true))
6312 if (com_token[0] == '!')
6315 origin[0] = atof(com_token+1);
6318 origin[0] = atof(com_token);
6323 while (*s && *s != '\n' && *s != '\r')
6329 // check for modifier flags
6336 #if _MSC_VER >= 1400
6337 #define sscanf sscanf_s
6339 cubemapname[sizeof(cubemapname)-1] = 0;
6340 #if MAX_QPATH != 128
6341 #error update this code if MAX_QPATH changes
6343 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
6344 #if _MSC_VER >= 1400
6345 , sizeof(cubemapname)
6347 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
6350 flags = LIGHTFLAG_REALTIMEMODE;
6358 coronasizescale = 0.25f;
6360 VectorClear(angles);
6363 if (a < 9 || !strcmp(cubemapname, "\"\""))
6365 // remove quotes on cubemapname
6366 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
6369 namelen = strlen(cubemapname) - 2;
6370 memmove(cubemapname, cubemapname + 1, namelen);
6371 cubemapname[namelen] = '\0';
6375 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);
6378 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6386 Con_Printf("invalid rtlights file \"%s\"\n", name);
6387 Mem_Free(lightsstring);
6391 void R_Shadow_SaveWorldLights(void)
6395 size_t bufchars, bufmaxchars;
6397 char name[MAX_QPATH];
6398 char line[MAX_INPUTLINE];
6399 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
6400 // I hate lines which are 3 times my screen size :( --blub
6403 if (cl.worldmodel == NULL)
6405 Con_Print("No map loaded.\n");
6408 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6409 bufchars = bufmaxchars = 0;
6411 for (lightindex = 0;lightindex < range;lightindex++)
6413 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6416 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
6417 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);
6418 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
6419 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]);
6421 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);
6422 if (bufchars + strlen(line) > bufmaxchars)
6424 bufmaxchars = bufchars + strlen(line) + 2048;
6426 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
6430 memcpy(buf, oldbuf, bufchars);
6436 memcpy(buf + bufchars, line, strlen(line));
6437 bufchars += strlen(line);
6441 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
6446 void R_Shadow_LoadLightsFile(void)
6449 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
6450 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
6451 if (cl.worldmodel == NULL)
6453 Con_Print("No map loaded.\n");
6456 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
6457 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6465 while (*s && *s != '\n' && *s != '\r')
6471 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);
6475 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);
6478 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
6479 radius = bound(15, radius, 4096);
6480 VectorScale(color, (2.0f / (8388608.0f)), color);
6481 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6489 Con_Printf("invalid lights file \"%s\"\n", name);
6490 Mem_Free(lightsstring);
6494 // tyrlite/hmap2 light types in the delay field
6495 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
6497 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
6509 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
6510 char key[256], value[MAX_INPUTLINE];
6513 if (cl.worldmodel == NULL)
6515 Con_Print("No map loaded.\n");
6518 // try to load a .ent file first
6519 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
6520 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
6521 // and if that is not found, fall back to the bsp file entity string
6523 data = cl.worldmodel->brush.entities;
6526 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
6528 type = LIGHTTYPE_MINUSX;
6529 origin[0] = origin[1] = origin[2] = 0;
6530 originhack[0] = originhack[1] = originhack[2] = 0;
6531 angles[0] = angles[1] = angles[2] = 0;
6532 color[0] = color[1] = color[2] = 1;
6533 light[0] = light[1] = light[2] = 1;light[3] = 300;
6534 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
6544 if (!COM_ParseToken_Simple(&data, false, false, true))
6546 if (com_token[0] == '}')
6547 break; // end of entity
6548 if (com_token[0] == '_')
6549 strlcpy(key, com_token + 1, sizeof(key));
6551 strlcpy(key, com_token, sizeof(key));
6552 while (key[strlen(key)-1] == ' ') // remove trailing spaces
6553 key[strlen(key)-1] = 0;
6554 if (!COM_ParseToken_Simple(&data, false, false, true))
6556 strlcpy(value, com_token, sizeof(value));
6558 // now that we have the key pair worked out...
6559 if (!strcmp("light", key))
6561 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
6565 light[0] = vec[0] * (1.0f / 256.0f);
6566 light[1] = vec[0] * (1.0f / 256.0f);
6567 light[2] = vec[0] * (1.0f / 256.0f);
6573 light[0] = vec[0] * (1.0f / 255.0f);
6574 light[1] = vec[1] * (1.0f / 255.0f);
6575 light[2] = vec[2] * (1.0f / 255.0f);
6579 else if (!strcmp("delay", key))
6581 else if (!strcmp("origin", key))
6582 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
6583 else if (!strcmp("angle", key))
6584 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
6585 else if (!strcmp("angles", key))
6586 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
6587 else if (!strcmp("color", key))
6588 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
6589 else if (!strcmp("wait", key))
6590 fadescale = atof(value);
6591 else if (!strcmp("classname", key))
6593 if (!strncmp(value, "light", 5))
6596 if (!strcmp(value, "light_fluoro"))
6601 overridecolor[0] = 1;
6602 overridecolor[1] = 1;
6603 overridecolor[2] = 1;
6605 if (!strcmp(value, "light_fluorospark"))
6610 overridecolor[0] = 1;
6611 overridecolor[1] = 1;
6612 overridecolor[2] = 1;
6614 if (!strcmp(value, "light_globe"))
6619 overridecolor[0] = 1;
6620 overridecolor[1] = 0.8;
6621 overridecolor[2] = 0.4;
6623 if (!strcmp(value, "light_flame_large_yellow"))
6628 overridecolor[0] = 1;
6629 overridecolor[1] = 0.5;
6630 overridecolor[2] = 0.1;
6632 if (!strcmp(value, "light_flame_small_yellow"))
6637 overridecolor[0] = 1;
6638 overridecolor[1] = 0.5;
6639 overridecolor[2] = 0.1;
6641 if (!strcmp(value, "light_torch_small_white"))
6646 overridecolor[0] = 1;
6647 overridecolor[1] = 0.5;
6648 overridecolor[2] = 0.1;
6650 if (!strcmp(value, "light_torch_small_walltorch"))
6655 overridecolor[0] = 1;
6656 overridecolor[1] = 0.5;
6657 overridecolor[2] = 0.1;
6661 else if (!strcmp("style", key))
6662 style = atoi(value);
6663 else if (!strcmp("skin", key))
6664 skin = (int)atof(value);
6665 else if (!strcmp("pflags", key))
6666 pflags = (int)atof(value);
6667 //else if (!strcmp("effects", key))
6668 // effects = (int)atof(value);
6669 else if (cl.worldmodel->type == mod_brushq3)
6671 if (!strcmp("scale", key))
6672 lightscale = atof(value);
6673 if (!strcmp("fade", key))
6674 fadescale = atof(value);
6679 if (lightscale <= 0)
6683 if (color[0] == color[1] && color[0] == color[2])
6685 color[0] *= overridecolor[0];
6686 color[1] *= overridecolor[1];
6687 color[2] *= overridecolor[2];
6689 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
6690 color[0] = color[0] * light[0];
6691 color[1] = color[1] * light[1];
6692 color[2] = color[2] * light[2];
6695 case LIGHTTYPE_MINUSX:
6697 case LIGHTTYPE_RECIPX:
6699 VectorScale(color, (1.0f / 16.0f), color);
6701 case LIGHTTYPE_RECIPXX:
6703 VectorScale(color, (1.0f / 16.0f), color);
6706 case LIGHTTYPE_NONE:
6710 case LIGHTTYPE_MINUSXX:
6713 VectorAdd(origin, originhack, origin);
6715 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);
6718 Mem_Free(entfiledata);
6722 static void R_Shadow_SetCursorLocationForView(void)
6725 vec3_t dest, endpos;
6727 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
6728 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true);
6729 if (trace.fraction < 1)
6731 dist = trace.fraction * r_editlights_cursordistance.value;
6732 push = r_editlights_cursorpushback.value;
6736 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
6737 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
6741 VectorClear( endpos );
6743 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6744 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6745 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6748 void R_Shadow_UpdateWorldLightSelection(void)
6750 if (r_editlights.integer)
6752 R_Shadow_SetCursorLocationForView();
6753 R_Shadow_SelectLightInView();
6756 R_Shadow_SelectLight(NULL);
6759 static void R_Shadow_EditLights_Clear_f(void)
6761 R_Shadow_ClearWorldLights();
6764 void R_Shadow_EditLights_Reload_f(void)
6768 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
6769 R_Shadow_ClearWorldLights();
6770 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
6772 R_Shadow_LoadWorldLights();
6773 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6774 R_Shadow_LoadLightsFile();
6776 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
6778 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6779 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6783 static void R_Shadow_EditLights_Save_f(void)
6787 R_Shadow_SaveWorldLights();
6790 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6792 R_Shadow_ClearWorldLights();
6793 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6796 static void R_Shadow_EditLights_ImportLightsFile_f(void)
6798 R_Shadow_ClearWorldLights();
6799 R_Shadow_LoadLightsFile();
6802 static void R_Shadow_EditLights_Spawn_f(void)
6805 if (!r_editlights.integer)
6807 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6810 if (Cmd_Argc() != 1)
6812 Con_Print("r_editlights_spawn does not take parameters\n");
6815 color[0] = color[1] = color[2] = 1;
6816 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6819 static void R_Shadow_EditLights_Edit_f(void)
6821 vec3_t origin, angles, color;
6822 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6823 int style, shadows, flags, normalmode, realtimemode;
6824 char cubemapname[MAX_INPUTLINE];
6825 if (!r_editlights.integer)
6827 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6830 if (!r_shadow_selectedlight)
6832 Con_Print("No selected light.\n");
6835 VectorCopy(r_shadow_selectedlight->origin, origin);
6836 VectorCopy(r_shadow_selectedlight->angles, angles);
6837 VectorCopy(r_shadow_selectedlight->color, color);
6838 radius = r_shadow_selectedlight->radius;
6839 style = r_shadow_selectedlight->style;
6840 if (r_shadow_selectedlight->cubemapname)
6841 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6844 shadows = r_shadow_selectedlight->shadow;
6845 corona = r_shadow_selectedlight->corona;
6846 coronasizescale = r_shadow_selectedlight->coronasizescale;
6847 ambientscale = r_shadow_selectedlight->ambientscale;
6848 diffusescale = r_shadow_selectedlight->diffusescale;
6849 specularscale = r_shadow_selectedlight->specularscale;
6850 flags = r_shadow_selectedlight->flags;
6851 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6852 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6853 if (!strcmp(Cmd_Argv(1), "origin"))
6855 if (Cmd_Argc() != 5)
6857 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6860 origin[0] = atof(Cmd_Argv(2));
6861 origin[1] = atof(Cmd_Argv(3));
6862 origin[2] = atof(Cmd_Argv(4));
6864 else if (!strcmp(Cmd_Argv(1), "originscale"))
6866 if (Cmd_Argc() != 5)
6868 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6871 origin[0] *= atof(Cmd_Argv(2));
6872 origin[1] *= atof(Cmd_Argv(3));
6873 origin[2] *= atof(Cmd_Argv(4));
6875 else if (!strcmp(Cmd_Argv(1), "originx"))
6877 if (Cmd_Argc() != 3)
6879 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6882 origin[0] = atof(Cmd_Argv(2));
6884 else if (!strcmp(Cmd_Argv(1), "originy"))
6886 if (Cmd_Argc() != 3)
6888 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6891 origin[1] = atof(Cmd_Argv(2));
6893 else if (!strcmp(Cmd_Argv(1), "originz"))
6895 if (Cmd_Argc() != 3)
6897 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6900 origin[2] = atof(Cmd_Argv(2));
6902 else if (!strcmp(Cmd_Argv(1), "move"))
6904 if (Cmd_Argc() != 5)
6906 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6909 origin[0] += atof(Cmd_Argv(2));
6910 origin[1] += atof(Cmd_Argv(3));
6911 origin[2] += atof(Cmd_Argv(4));
6913 else if (!strcmp(Cmd_Argv(1), "movex"))
6915 if (Cmd_Argc() != 3)
6917 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6920 origin[0] += atof(Cmd_Argv(2));
6922 else if (!strcmp(Cmd_Argv(1), "movey"))
6924 if (Cmd_Argc() != 3)
6926 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6929 origin[1] += atof(Cmd_Argv(2));
6931 else if (!strcmp(Cmd_Argv(1), "movez"))
6933 if (Cmd_Argc() != 3)
6935 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6938 origin[2] += atof(Cmd_Argv(2));
6940 else if (!strcmp(Cmd_Argv(1), "angles"))
6942 if (Cmd_Argc() != 5)
6944 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6947 angles[0] = atof(Cmd_Argv(2));
6948 angles[1] = atof(Cmd_Argv(3));
6949 angles[2] = atof(Cmd_Argv(4));
6951 else if (!strcmp(Cmd_Argv(1), "anglesx"))
6953 if (Cmd_Argc() != 3)
6955 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6958 angles[0] = atof(Cmd_Argv(2));
6960 else if (!strcmp(Cmd_Argv(1), "anglesy"))
6962 if (Cmd_Argc() != 3)
6964 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6967 angles[1] = atof(Cmd_Argv(2));
6969 else if (!strcmp(Cmd_Argv(1), "anglesz"))
6971 if (Cmd_Argc() != 3)
6973 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6976 angles[2] = atof(Cmd_Argv(2));
6978 else if (!strcmp(Cmd_Argv(1), "color"))
6980 if (Cmd_Argc() != 5)
6982 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
6985 color[0] = atof(Cmd_Argv(2));
6986 color[1] = atof(Cmd_Argv(3));
6987 color[2] = atof(Cmd_Argv(4));
6989 else if (!strcmp(Cmd_Argv(1), "radius"))
6991 if (Cmd_Argc() != 3)
6993 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6996 radius = atof(Cmd_Argv(2));
6998 else if (!strcmp(Cmd_Argv(1), "colorscale"))
7000 if (Cmd_Argc() == 3)
7002 double scale = atof(Cmd_Argv(2));
7009 if (Cmd_Argc() != 5)
7011 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
7014 color[0] *= atof(Cmd_Argv(2));
7015 color[1] *= atof(Cmd_Argv(3));
7016 color[2] *= atof(Cmd_Argv(4));
7019 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
7021 if (Cmd_Argc() != 3)
7023 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7026 radius *= atof(Cmd_Argv(2));
7028 else if (!strcmp(Cmd_Argv(1), "style"))
7030 if (Cmd_Argc() != 3)
7032 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7035 style = atoi(Cmd_Argv(2));
7037 else if (!strcmp(Cmd_Argv(1), "cubemap"))
7041 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7044 if (Cmd_Argc() == 3)
7045 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
7049 else if (!strcmp(Cmd_Argv(1), "shadows"))
7051 if (Cmd_Argc() != 3)
7053 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7056 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7058 else if (!strcmp(Cmd_Argv(1), "corona"))
7060 if (Cmd_Argc() != 3)
7062 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7065 corona = atof(Cmd_Argv(2));
7067 else if (!strcmp(Cmd_Argv(1), "coronasize"))
7069 if (Cmd_Argc() != 3)
7071 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7074 coronasizescale = atof(Cmd_Argv(2));
7076 else if (!strcmp(Cmd_Argv(1), "ambient"))
7078 if (Cmd_Argc() != 3)
7080 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7083 ambientscale = atof(Cmd_Argv(2));
7085 else if (!strcmp(Cmd_Argv(1), "diffuse"))
7087 if (Cmd_Argc() != 3)
7089 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7092 diffusescale = atof(Cmd_Argv(2));
7094 else if (!strcmp(Cmd_Argv(1), "specular"))
7096 if (Cmd_Argc() != 3)
7098 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7101 specularscale = atof(Cmd_Argv(2));
7103 else if (!strcmp(Cmd_Argv(1), "normalmode"))
7105 if (Cmd_Argc() != 3)
7107 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7110 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7112 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
7114 if (Cmd_Argc() != 3)
7116 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7119 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7123 Con_Print("usage: r_editlights_edit [property] [value]\n");
7124 Con_Print("Selected light's properties:\n");
7125 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7126 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7127 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7128 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
7129 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
7130 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
7131 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
7132 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
7133 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
7134 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
7135 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
7136 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
7137 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
7138 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
7141 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
7142 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
7145 static void R_Shadow_EditLights_EditAll_f(void)
7148 dlight_t *light, *oldselected;
7151 if (!r_editlights.integer)
7153 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
7157 oldselected = r_shadow_selectedlight;
7158 // EditLights doesn't seem to have a "remove" command or something so:
7159 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7160 for (lightindex = 0;lightindex < range;lightindex++)
7162 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7165 R_Shadow_SelectLight(light);
7166 R_Shadow_EditLights_Edit_f();
7168 // return to old selected (to not mess editing once selection is locked)
7169 R_Shadow_SelectLight(oldselected);
7172 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
7174 int lightnumber, lightcount;
7175 size_t lightindex, range;
7180 if (!r_editlights.integer)
7183 // update cvars so QC can query them
7184 if (r_shadow_selectedlight)
7186 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7187 Cvar_SetQuick(&r_editlights_current_origin, temp);
7188 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7189 Cvar_SetQuick(&r_editlights_current_angles, temp);
7190 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7191 Cvar_SetQuick(&r_editlights_current_color, temp);
7192 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
7193 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
7194 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
7195 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
7196 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
7197 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
7198 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
7199 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
7200 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
7201 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
7202 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
7205 // draw properties on screen
7206 if (!r_editlights_drawproperties.integer)
7208 x = vid_conwidth.value - 320;
7210 DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
7213 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7214 for (lightindex = 0;lightindex < range;lightindex++)
7216 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7219 if (light == r_shadow_selectedlight)
7220 lightnumber = (int)lightindex;
7223 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;
7224 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;
7226 if (r_shadow_selectedlight == NULL)
7228 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;
7229 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;
7230 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;
7231 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;
7232 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;
7233 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;
7234 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;
7235 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;
7236 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;
7237 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;
7238 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;
7239 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;
7240 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;
7241 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;
7242 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;
7244 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;
7245 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;
7246 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;
7247 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;
7248 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;
7249 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;
7250 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;
7251 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;
7252 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;
7253 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;
7256 static void R_Shadow_EditLights_ToggleShadow_f(void)
7258 if (!r_editlights.integer)
7260 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7263 if (!r_shadow_selectedlight)
7265 Con_Print("No selected light.\n");
7268 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);
7271 static void R_Shadow_EditLights_ToggleCorona_f(void)
7273 if (!r_editlights.integer)
7275 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7278 if (!r_shadow_selectedlight)
7280 Con_Print("No selected light.\n");
7283 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);
7286 static void R_Shadow_EditLights_Remove_f(void)
7288 if (!r_editlights.integer)
7290 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
7293 if (!r_shadow_selectedlight)
7295 Con_Print("No selected light.\n");
7298 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
7299 r_shadow_selectedlight = NULL;
7302 static void R_Shadow_EditLights_Help_f(void)
7305 "Documentation on r_editlights system:\n"
7307 "r_editlights : enable/disable editing mode\n"
7308 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
7309 "r_editlights_cursorpushback : push back cursor this far from surface\n"
7310 "r_editlights_cursorpushoff : push cursor off surface this far\n"
7311 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
7312 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
7314 "r_editlights_help : this help\n"
7315 "r_editlights_clear : remove all lights\n"
7316 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
7317 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
7318 "r_editlights_save : save to .rtlights file\n"
7319 "r_editlights_spawn : create a light with default settings\n"
7320 "r_editlights_edit command : edit selected light - more documentation below\n"
7321 "r_editlights_remove : remove selected light\n"
7322 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
7323 "r_editlights_importlightentitiesfrommap : reload light entities\n"
7324 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
7326 "origin x y z : set light location\n"
7327 "originx x: set x component of light location\n"
7328 "originy y: set y component of light location\n"
7329 "originz z: set z component of light location\n"
7330 "move x y z : adjust light location\n"
7331 "movex x: adjust x component of light location\n"
7332 "movey y: adjust y component of light location\n"
7333 "movez z: adjust z component of light location\n"
7334 "angles x y z : set light angles\n"
7335 "anglesx x: set x component of light angles\n"
7336 "anglesy y: set y component of light angles\n"
7337 "anglesz z: set z component of light angles\n"
7338 "color r g b : set color of light (can be brighter than 1 1 1)\n"
7339 "radius radius : set radius (size) of light\n"
7340 "colorscale grey : multiply color of light (1 does nothing)\n"
7341 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
7342 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
7343 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
7344 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
7345 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
7346 "cubemap basename : set filter cubemap of light\n"
7347 "shadows 1/0 : turn on/off shadows\n"
7348 "corona n : set corona intensity\n"
7349 "coronasize n : set corona size (0-1)\n"
7350 "ambient n : set ambient intensity (0-1)\n"
7351 "diffuse n : set diffuse intensity (0-1)\n"
7352 "specular n : set specular intensity (0-1)\n"
7353 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
7354 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
7355 "<nothing> : print light properties to console\n"
7359 static void R_Shadow_EditLights_CopyInfo_f(void)
7361 if (!r_editlights.integer)
7363 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
7366 if (!r_shadow_selectedlight)
7368 Con_Print("No selected light.\n");
7371 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
7372 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
7373 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
7374 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
7375 if (r_shadow_selectedlight->cubemapname)
7376 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
7378 r_shadow_bufferlight.cubemapname[0] = 0;
7379 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
7380 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
7381 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
7382 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
7383 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
7384 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
7385 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
7388 static void R_Shadow_EditLights_PasteInfo_f(void)
7390 if (!r_editlights.integer)
7392 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
7395 if (!r_shadow_selectedlight)
7397 Con_Print("No selected light.\n");
7400 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);
7403 static void R_Shadow_EditLights_Lock_f(void)
7405 if (!r_editlights.integer)
7407 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
7410 if (r_editlights_lockcursor)
7412 r_editlights_lockcursor = false;
7415 if (!r_shadow_selectedlight)
7417 Con_Print("No selected light to lock on.\n");
7420 r_editlights_lockcursor = true;
7423 static void R_Shadow_EditLights_Init(void)
7425 Cvar_RegisterVariable(&r_editlights);
7426 Cvar_RegisterVariable(&r_editlights_cursordistance);
7427 Cvar_RegisterVariable(&r_editlights_cursorpushback);
7428 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
7429 Cvar_RegisterVariable(&r_editlights_cursorgrid);
7430 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
7431 Cvar_RegisterVariable(&r_editlights_drawproperties);
7432 Cvar_RegisterVariable(&r_editlights_current_origin);
7433 Cvar_RegisterVariable(&r_editlights_current_angles);
7434 Cvar_RegisterVariable(&r_editlights_current_color);
7435 Cvar_RegisterVariable(&r_editlights_current_radius);
7436 Cvar_RegisterVariable(&r_editlights_current_corona);
7437 Cvar_RegisterVariable(&r_editlights_current_coronasize);
7438 Cvar_RegisterVariable(&r_editlights_current_style);
7439 Cvar_RegisterVariable(&r_editlights_current_shadows);
7440 Cvar_RegisterVariable(&r_editlights_current_cubemap);
7441 Cvar_RegisterVariable(&r_editlights_current_ambient);
7442 Cvar_RegisterVariable(&r_editlights_current_diffuse);
7443 Cvar_RegisterVariable(&r_editlights_current_specular);
7444 Cvar_RegisterVariable(&r_editlights_current_normalmode);
7445 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
7446 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
7447 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
7448 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)");
7449 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
7450 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
7451 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
7452 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)");
7453 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
7454 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
7455 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
7456 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
7457 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
7458 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
7459 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)");
7460 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
7466 =============================================================================
7470 =============================================================================
7473 void R_LightPoint(float *color, const vec3_t p, const int flags)
7475 int i, numlights, flag;
7476 float f, relativepoint[3], dist, dist2, lightradius2;
7481 if (r_fullbright.integer)
7483 VectorSet(color, 1, 1, 1);
7489 if (flags & LP_LIGHTMAP)
7491 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7493 VectorClear(diffuse);
7494 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, color, diffuse, n);
7495 VectorAdd(color, diffuse, color);
7498 VectorSet(color, 1, 1, 1);
7499 color[0] += r_refdef.scene.ambient;
7500 color[1] += r_refdef.scene.ambient;
7501 color[2] += r_refdef.scene.ambient;
7504 if (flags & LP_RTWORLD)
7506 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7507 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7508 for (i = 0; i < numlights; i++)
7510 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7513 light = &dlight->rtlight;
7514 if (!(light->flags & flag))
7517 lightradius2 = light->radius * light->radius;
7518 VectorSubtract(light->shadoworigin, p, relativepoint);
7519 dist2 = VectorLength2(relativepoint);
7520 if (dist2 >= lightradius2)
7522 dist = sqrt(dist2) / light->radius;
7523 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7526 // todo: add to both ambient and diffuse
7527 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1)
7528 VectorMA(color, f, light->currentcolor, color);
7531 if (flags & LP_DYNLIGHT)
7534 for (i = 0;i < r_refdef.scene.numlights;i++)
7536 light = r_refdef.scene.lights[i];
7538 lightradius2 = light->radius * light->radius;
7539 VectorSubtract(light->shadoworigin, p, relativepoint);
7540 dist2 = VectorLength2(relativepoint);
7541 if (dist2 >= lightradius2)
7543 dist = sqrt(dist2) / light->radius;
7544 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7547 // todo: add to both ambient and diffuse
7548 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1)
7549 VectorMA(color, f, light->color, color);
7554 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
7556 int i, numlights, flag;
7559 float relativepoint[3];
7568 if (r_fullbright.integer)
7570 VectorSet(ambient, 1, 1, 1);
7571 VectorClear(diffuse);
7572 VectorClear(lightdir);
7576 if (flags == LP_LIGHTMAP)
7578 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7579 VectorClear(diffuse);
7580 VectorClear(lightdir);
7581 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7582 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
7584 VectorSet(ambient, 1, 1, 1);
7588 memset(sample, 0, sizeof(sample));
7589 VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7591 if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7594 VectorClear(tempambient);
7596 VectorClear(relativepoint);
7597 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
7598 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
7599 VectorScale(color, r_refdef.lightmapintensity, color);
7600 VectorAdd(sample, tempambient, sample);
7601 VectorMA(sample , 0.5f , color, sample );
7602 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7603 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7604 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7605 // calculate a weighted average light direction as well
7606 intensity = VectorLength(color);
7607 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7610 if (flags & LP_RTWORLD)
7612 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7613 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7614 for (i = 0; i < numlights; i++)
7616 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7619 light = &dlight->rtlight;
7620 if (!(light->flags & flag))
7623 lightradius2 = light->radius * light->radius;
7624 VectorSubtract(light->shadoworigin, p, relativepoint);
7625 dist2 = VectorLength2(relativepoint);
7626 if (dist2 >= lightradius2)
7628 dist = sqrt(dist2) / light->radius;
7629 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
7630 if (intensity <= 0.0f)
7632 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
7634 // scale down intensity to add to both ambient and diffuse
7635 //intensity *= 0.5f;
7636 VectorNormalize(relativepoint);
7637 VectorScale(light->currentcolor, intensity, color);
7638 VectorMA(sample , 0.5f , color, sample );
7639 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7640 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7641 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7642 // calculate a weighted average light direction as well
7643 intensity *= VectorLength(color);
7644 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7646 // FIXME: sample bouncegrid too!
7649 if (flags & LP_DYNLIGHT)
7652 for (i = 0;i < r_refdef.scene.numlights;i++)
7654 light = r_refdef.scene.lights[i];
7656 lightradius2 = light->radius * light->radius;
7657 VectorSubtract(light->shadoworigin, p, relativepoint);
7658 dist2 = VectorLength2(relativepoint);
7659 if (dist2 >= lightradius2)
7661 dist = sqrt(dist2) / light->radius;
7662 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
7663 if (intensity <= 0.0f)
7665 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
7667 // scale down intensity to add to both ambient and diffuse
7668 //intensity *= 0.5f;
7669 VectorNormalize(relativepoint);
7670 VectorScale(light->currentcolor, intensity, color);
7671 VectorMA(sample , 0.5f , color, sample );
7672 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7673 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7674 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7675 // calculate a weighted average light direction as well
7676 intensity *= VectorLength(color);
7677 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7681 // calculate the direction we'll use to reduce the sample to a directional light source
7682 VectorCopy(sample + 12, dir);
7683 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
7684 VectorNormalize(dir);
7685 // extract the diffuse color along the chosen direction and scale it
7686 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
7687 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
7688 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
7689 // subtract some of diffuse from ambient
7690 VectorMA(sample, -0.333f, diffuse, ambient);
7691 // store the normalized lightdir
7692 VectorCopy(dir, lightdir);