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", "1", "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_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)"};
341 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"};
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_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
344 cvar_t r_shadow_bouncegrid_dynamic_energyperphoton = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_energyperphoton", "10000", "amount of light that one photon should represent"};
345 cvar_t r_shadow_bouncegrid_dynamic_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_lightradiusscale", "10", "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", "5", "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_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_spacing", "64", "unit size of bouncegrid pixel"};
349 cvar_t r_shadow_bouncegrid_dynamic_stablerandom = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_stablerandom", "1", "make particle distribution consistent from frame to frame"};
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_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"};
358 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "0.25", "brightness of particles contributing to bouncegrid texture"};
359 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"};
360 cvar_t r_shadow_bouncegrid_lightpathsize = {CVAR_SAVE, "r_shadow_bouncegrid_lightpathsize", "1", "width of the light path for accumulation of light in the bouncegrid texture"};
361 cvar_t r_shadow_bouncegrid_static = {CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
362 cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
363 cvar_t r_shadow_bouncegrid_static_energyperphoton = {CVAR_SAVE, "r_shadow_bouncegrid_static_energyperphoton", "10000", "amount of light that one photon should represent in static mode"};
364 cvar_t r_shadow_bouncegrid_static_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_static_lightradiusscale", "10", "particles stop at this fraction of light radius (can be more than 1) when in static mode"};
365 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"};
366 cvar_t r_shadow_bouncegrid_static_maxphotons = {CVAR_SAVE, "r_shadow_bouncegrid_static_maxphotons", "250000", "upper bound on photons in static mode"};
367 cvar_t r_shadow_bouncegrid_static_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_static_spacing", "64", "unit size of bouncegrid pixel when in static mode"};
368 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
369 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"};
370 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!"};
371 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
372 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
373 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
374 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
375 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
376 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
377 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
378 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
379 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
380 cvar_t r_editlights_drawproperties = {0, "r_editlights_drawproperties", "1", "draw properties of currently selected light"};
381 cvar_t r_editlights_current_origin = {0, "r_editlights_current_origin", "0 0 0", "origin of selected light"};
382 cvar_t r_editlights_current_angles = {0, "r_editlights_current_angles", "0 0 0", "angles of selected light"};
383 cvar_t r_editlights_current_color = {0, "r_editlights_current_color", "1 1 1", "color of selected light"};
384 cvar_t r_editlights_current_radius = {0, "r_editlights_current_radius", "0", "radius of selected light"};
385 cvar_t r_editlights_current_corona = {0, "r_editlights_current_corona", "0", "corona intensity of selected light"};
386 cvar_t r_editlights_current_coronasize = {0, "r_editlights_current_coronasize", "0", "corona size of selected light"};
387 cvar_t r_editlights_current_style = {0, "r_editlights_current_style", "0", "style of selected light"};
388 cvar_t r_editlights_current_shadows = {0, "r_editlights_current_shadows", "0", "shadows flag of selected light"};
389 cvar_t r_editlights_current_cubemap = {0, "r_editlights_current_cubemap", "0", "cubemap of selected light"};
390 cvar_t r_editlights_current_ambient = {0, "r_editlights_current_ambient", "0", "ambient intensity of selected light"};
391 cvar_t r_editlights_current_diffuse = {0, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"};
392 cvar_t r_editlights_current_specular = {0, "r_editlights_current_specular", "1", "specular intensity of selected light"};
393 cvar_t r_editlights_current_normalmode = {0, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"};
394 cvar_t r_editlights_current_realtimemode = {0, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"};
396 r_shadow_bouncegrid_state_t r_shadow_bouncegrid_state;
398 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
399 #define ATTENTABLESIZE 256
400 // 1D gradient, 2D circle and 3D sphere attenuation textures
401 #define ATTEN1DSIZE 32
402 #define ATTEN2DSIZE 64
403 #define ATTEN3DSIZE 32
405 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
406 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
407 static float r_shadow_attentable[ATTENTABLESIZE+1];
409 rtlight_t *r_shadow_compilingrtlight;
410 static memexpandablearray_t r_shadow_worldlightsarray;
411 dlight_t *r_shadow_selectedlight;
412 dlight_t r_shadow_bufferlight;
413 vec3_t r_editlights_cursorlocation;
414 qboolean r_editlights_lockcursor;
416 extern int con_vislines;
418 void R_Shadow_UncompileWorldLights(void);
419 void R_Shadow_ClearWorldLights(void);
420 void R_Shadow_SaveWorldLights(void);
421 void R_Shadow_LoadWorldLights(void);
422 void R_Shadow_LoadLightsFile(void);
423 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
424 void R_Shadow_EditLights_Reload_f(void);
425 void R_Shadow_ValidateCvars(void);
426 static void R_Shadow_MakeTextures(void);
428 #define EDLIGHTSPRSIZE 8
429 skinframe_t *r_editlights_sprcursor;
430 skinframe_t *r_editlights_sprlight;
431 skinframe_t *r_editlights_sprnoshadowlight;
432 skinframe_t *r_editlights_sprcubemaplight;
433 skinframe_t *r_editlights_sprcubemapnoshadowlight;
434 skinframe_t *r_editlights_sprselection;
436 static void R_Shadow_DrawModelShadowMaps(void);
437 static void R_Shadow_MakeShadowMap(int texturesize);
438 static void R_Shadow_MakeVSDCT(void);
439 static void R_Shadow_SetShadowMode(void)
441 r_shadow_shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
442 r_shadow_shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
443 r_shadow_shadowmapmaxsize = bound(r_shadow_shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, r_shadow_shadowmaptexturesize / 8);
444 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
445 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
446 r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
447 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
448 r_shadow_shadowmapsampler = false;
449 r_shadow_shadowmappcf = 0;
450 r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
451 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
452 Mod_AllocLightmap_Init(&r_shadow_shadowmapatlas_state, r_main_mempool, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize);
453 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
455 switch(vid.renderpath)
457 case RENDERPATH_GL20:
458 if(r_shadow_shadowmapfilterquality < 0)
460 if (!r_fb.usedepthtextures)
461 r_shadow_shadowmappcf = 1;
462 else if((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && vid.support.arb_shadow && r_shadow_shadowmapshadowsampler)
464 r_shadow_shadowmapsampler = true;
465 r_shadow_shadowmappcf = 1;
467 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
468 r_shadow_shadowmappcf = 1;
469 else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa"))
470 r_shadow_shadowmappcf = 1;
472 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
476 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
477 switch (r_shadow_shadowmapfilterquality)
482 r_shadow_shadowmappcf = 1;
485 r_shadow_shadowmappcf = 1;
488 r_shadow_shadowmappcf = 2;
492 if (!r_fb.usedepthtextures)
493 r_shadow_shadowmapsampler = false;
494 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
496 case RENDERPATH_D3D9:
497 case RENDERPATH_D3D10:
498 case RENDERPATH_D3D11:
499 case RENDERPATH_SOFT:
500 r_shadow_shadowmapsampler = false;
501 r_shadow_shadowmappcf = 1;
502 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
504 case RENDERPATH_GL11:
505 case RENDERPATH_GL13:
506 case RENDERPATH_GLES1:
507 case RENDERPATH_GLES2:
512 if(R_CompileShader_CheckStaticParms())
516 qboolean R_Shadow_ShadowMappingEnabled(void)
518 switch (r_shadow_shadowmode)
520 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
527 static void R_Shadow_FreeShadowMaps(void)
529 Mod_AllocLightmap_Free(&r_shadow_shadowmapatlas_state);
531 R_Shadow_SetShadowMode();
533 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
537 if (r_shadow_shadowmap2ddepthtexture)
538 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
539 r_shadow_shadowmap2ddepthtexture = NULL;
541 if (r_shadow_shadowmap2ddepthbuffer)
542 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
543 r_shadow_shadowmap2ddepthbuffer = NULL;
545 if (r_shadow_shadowmapvsdcttexture)
546 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
547 r_shadow_shadowmapvsdcttexture = NULL;
550 static void r_shadow_start(void)
552 // allocate vertex processing arrays
553 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
554 r_shadow_attenuationgradienttexture = NULL;
555 r_shadow_attenuation2dtexture = NULL;
556 r_shadow_attenuation3dtexture = NULL;
557 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
558 r_shadow_shadowmap2ddepthtexture = NULL;
559 r_shadow_shadowmap2ddepthbuffer = NULL;
560 r_shadow_shadowmapvsdcttexture = NULL;
561 r_shadow_shadowmapmaxsize = 0;
562 r_shadow_shadowmaptexturesize = 0;
563 r_shadow_shadowmapfilterquality = -1;
564 r_shadow_shadowmapdepthbits = 0;
565 r_shadow_shadowmapvsdct = false;
566 r_shadow_shadowmapsampler = false;
567 r_shadow_shadowmappcf = 0;
570 R_Shadow_FreeShadowMaps();
572 r_shadow_texturepool = NULL;
573 r_shadow_filters_texturepool = NULL;
574 R_Shadow_ValidateCvars();
575 R_Shadow_MakeTextures();
576 r_shadow_scenemaxlights = 0;
577 r_shadow_scenenumlights = 0;
578 r_shadow_scenelightlist = NULL;
579 maxshadowtriangles = 0;
580 shadowelements = NULL;
581 maxshadowvertices = 0;
582 shadowvertex3f = NULL;
590 shadowmarklist = NULL;
595 shadowsideslist = NULL;
596 r_shadow_buffer_numleafpvsbytes = 0;
597 r_shadow_buffer_visitingleafpvs = NULL;
598 r_shadow_buffer_leafpvs = NULL;
599 r_shadow_buffer_leaflist = NULL;
600 r_shadow_buffer_numsurfacepvsbytes = 0;
601 r_shadow_buffer_surfacepvs = NULL;
602 r_shadow_buffer_surfacelist = NULL;
603 r_shadow_buffer_surfacesides = NULL;
604 r_shadow_buffer_numshadowtrispvsbytes = 0;
605 r_shadow_buffer_shadowtrispvs = NULL;
606 r_shadow_buffer_numlighttrispvsbytes = 0;
607 r_shadow_buffer_lighttrispvs = NULL;
609 r_shadow_usingdeferredprepass = false;
610 r_shadow_prepass_width = r_shadow_prepass_height = 0;
612 // determine renderpath specific capabilities, we don't need to figure
613 // these out per frame...
614 switch(vid.renderpath)
616 case RENDERPATH_GL20:
617 r_shadow_bouncegrid_state.allowdirectionalshading = true;
618 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
620 case RENDERPATH_GLES2:
621 // for performance reasons, do not use directional shading on GLES devices
622 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
624 // these renderpaths do not currently have the code to display the bouncegrid, so disable it on them...
625 case RENDERPATH_GL11:
626 case RENDERPATH_GL13:
627 case RENDERPATH_GLES1:
628 case RENDERPATH_SOFT:
629 case RENDERPATH_D3D9:
630 case RENDERPATH_D3D10:
631 case RENDERPATH_D3D11:
636 static void R_Shadow_FreeDeferred(void);
637 static void r_shadow_shutdown(void)
640 R_Shadow_UncompileWorldLights();
642 R_Shadow_FreeShadowMaps();
644 r_shadow_usingdeferredprepass = false;
645 if (r_shadow_prepass_width)
646 R_Shadow_FreeDeferred();
647 r_shadow_prepass_width = r_shadow_prepass_height = 0;
650 r_shadow_scenemaxlights = 0;
651 r_shadow_scenenumlights = 0;
652 if (r_shadow_scenelightlist)
653 Mem_Free(r_shadow_scenelightlist);
654 r_shadow_scenelightlist = NULL;
655 r_shadow_bouncegrid_state.highpixels = NULL;
656 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
657 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
658 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
659 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
660 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
661 r_shadow_bouncegrid_state.maxsplatpaths = 0;
662 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
663 r_shadow_attenuationgradienttexture = NULL;
664 r_shadow_attenuation2dtexture = NULL;
665 r_shadow_attenuation3dtexture = NULL;
666 R_FreeTexturePool(&r_shadow_texturepool);
667 R_FreeTexturePool(&r_shadow_filters_texturepool);
668 maxshadowtriangles = 0;
670 Mem_Free(shadowelements);
671 shadowelements = NULL;
673 Mem_Free(shadowvertex3f);
674 shadowvertex3f = NULL;
677 Mem_Free(vertexupdate);
680 Mem_Free(vertexremap);
686 Mem_Free(shadowmark);
689 Mem_Free(shadowmarklist);
690 shadowmarklist = NULL;
695 Mem_Free(shadowsides);
698 Mem_Free(shadowsideslist);
699 shadowsideslist = NULL;
700 r_shadow_buffer_numleafpvsbytes = 0;
701 if (r_shadow_buffer_visitingleafpvs)
702 Mem_Free(r_shadow_buffer_visitingleafpvs);
703 r_shadow_buffer_visitingleafpvs = NULL;
704 if (r_shadow_buffer_leafpvs)
705 Mem_Free(r_shadow_buffer_leafpvs);
706 r_shadow_buffer_leafpvs = NULL;
707 if (r_shadow_buffer_leaflist)
708 Mem_Free(r_shadow_buffer_leaflist);
709 r_shadow_buffer_leaflist = NULL;
710 r_shadow_buffer_numsurfacepvsbytes = 0;
711 if (r_shadow_buffer_surfacepvs)
712 Mem_Free(r_shadow_buffer_surfacepvs);
713 r_shadow_buffer_surfacepvs = NULL;
714 if (r_shadow_buffer_surfacelist)
715 Mem_Free(r_shadow_buffer_surfacelist);
716 r_shadow_buffer_surfacelist = NULL;
717 if (r_shadow_buffer_surfacesides)
718 Mem_Free(r_shadow_buffer_surfacesides);
719 r_shadow_buffer_surfacesides = NULL;
720 r_shadow_buffer_numshadowtrispvsbytes = 0;
721 if (r_shadow_buffer_shadowtrispvs)
722 Mem_Free(r_shadow_buffer_shadowtrispvs);
723 r_shadow_buffer_numlighttrispvsbytes = 0;
724 if (r_shadow_buffer_lighttrispvs)
725 Mem_Free(r_shadow_buffer_lighttrispvs);
728 static void r_shadow_newmap(void)
730 r_shadow_bouncegrid_state.highpixels = NULL;
731 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
732 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
733 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
734 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
735 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
736 r_shadow_bouncegrid_state.maxsplatpaths = 0;
737 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
738 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
739 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
740 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
741 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
742 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
743 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
744 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
745 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
746 R_Shadow_EditLights_Reload_f();
749 void R_Shadow_Init(void)
751 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
752 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
753 Cvar_RegisterVariable(&r_shadow_usebihculling);
754 Cvar_RegisterVariable(&r_shadow_usenormalmap);
755 Cvar_RegisterVariable(&r_shadow_debuglight);
756 Cvar_RegisterVariable(&r_shadow_deferred);
757 Cvar_RegisterVariable(&r_shadow_gloss);
758 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
759 Cvar_RegisterVariable(&r_shadow_glossintensity);
760 Cvar_RegisterVariable(&r_shadow_glossexponent);
761 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
762 Cvar_RegisterVariable(&r_shadow_glossexact);
763 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
764 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
765 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
766 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
767 Cvar_RegisterVariable(&r_shadow_projectdistance);
768 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
769 Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
770 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
771 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
772 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
773 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
774 Cvar_RegisterVariable(&r_shadow_realtime_world);
775 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
776 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
777 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
778 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
779 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
780 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
781 Cvar_RegisterVariable(&r_shadow_scissor);
782 Cvar_RegisterVariable(&r_shadow_shadowmapping);
783 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
784 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
785 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
786 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
787 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
788 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
789 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
790 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturesize);
791 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
792 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
793 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
794 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
795 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
796 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
797 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
798 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
799 Cvar_RegisterVariable(&r_shadow_polygonfactor);
800 Cvar_RegisterVariable(&r_shadow_polygonoffset);
801 Cvar_RegisterVariable(&r_shadow_texture3d);
802 Cvar_RegisterVariable(&r_shadow_bouncegrid);
803 Cvar_RegisterVariable(&r_shadow_bouncegrid_blur);
804 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
805 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_culllightpaths);
806 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_directionalshading);
807 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_dlightparticlemultiplier);
808 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_hitmodels);
809 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_energyperphoton);
810 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_lightradiusscale);
811 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxbounce);
812 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxphotons);
813 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_spacing);
814 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_stablerandom);
815 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_updateinterval);
816 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_x);
817 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_y);
818 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_z);
819 Cvar_RegisterVariable(&r_shadow_bouncegrid_floatcolors);
820 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
821 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
822 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize);
823 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
824 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
825 Cvar_RegisterVariable(&r_shadow_bouncegrid_sortlightpaths);
826 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
827 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_spacing);
828 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
829 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
830 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
831 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxphotons);
832 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_energyperphoton);
833 Cvar_RegisterVariable(&r_coronas);
834 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
835 Cvar_RegisterVariable(&r_coronas_occlusionquery);
836 Cvar_RegisterVariable(&gl_flashblend);
837 Cvar_RegisterVariable(&gl_ext_separatestencil);
838 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
839 R_Shadow_EditLights_Init();
840 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
841 r_shadow_scenemaxlights = 0;
842 r_shadow_scenenumlights = 0;
843 r_shadow_scenelightlist = NULL;
844 maxshadowtriangles = 0;
845 shadowelements = NULL;
846 maxshadowvertices = 0;
847 shadowvertex3f = NULL;
855 shadowmarklist = NULL;
860 shadowsideslist = NULL;
861 r_shadow_buffer_numleafpvsbytes = 0;
862 r_shadow_buffer_visitingleafpvs = NULL;
863 r_shadow_buffer_leafpvs = NULL;
864 r_shadow_buffer_leaflist = NULL;
865 r_shadow_buffer_numsurfacepvsbytes = 0;
866 r_shadow_buffer_surfacepvs = NULL;
867 r_shadow_buffer_surfacelist = NULL;
868 r_shadow_buffer_surfacesides = NULL;
869 r_shadow_buffer_shadowtrispvs = NULL;
870 r_shadow_buffer_lighttrispvs = NULL;
871 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
874 matrix4x4_t matrix_attenuationxyz =
877 {0.5, 0.0, 0.0, 0.5},
878 {0.0, 0.5, 0.0, 0.5},
879 {0.0, 0.0, 0.5, 0.5},
884 matrix4x4_t matrix_attenuationz =
887 {0.0, 0.0, 0.5, 0.5},
888 {0.0, 0.0, 0.0, 0.5},
889 {0.0, 0.0, 0.0, 0.5},
894 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
896 numvertices = ((numvertices + 255) & ~255) * vertscale;
897 numtriangles = ((numtriangles + 255) & ~255) * triscale;
898 // make sure shadowelements is big enough for this volume
899 if (maxshadowtriangles < numtriangles)
901 maxshadowtriangles = numtriangles;
903 Mem_Free(shadowelements);
904 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
906 // make sure shadowvertex3f is big enough for this volume
907 if (maxshadowvertices < numvertices)
909 maxshadowvertices = numvertices;
911 Mem_Free(shadowvertex3f);
912 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
916 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
918 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
919 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
920 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
921 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
922 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
924 if (r_shadow_buffer_visitingleafpvs)
925 Mem_Free(r_shadow_buffer_visitingleafpvs);
926 if (r_shadow_buffer_leafpvs)
927 Mem_Free(r_shadow_buffer_leafpvs);
928 if (r_shadow_buffer_leaflist)
929 Mem_Free(r_shadow_buffer_leaflist);
930 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
931 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
932 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
933 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
935 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
937 if (r_shadow_buffer_surfacepvs)
938 Mem_Free(r_shadow_buffer_surfacepvs);
939 if (r_shadow_buffer_surfacelist)
940 Mem_Free(r_shadow_buffer_surfacelist);
941 if (r_shadow_buffer_surfacesides)
942 Mem_Free(r_shadow_buffer_surfacesides);
943 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
944 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
945 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
946 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
948 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
950 if (r_shadow_buffer_shadowtrispvs)
951 Mem_Free(r_shadow_buffer_shadowtrispvs);
952 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
953 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
955 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
957 if (r_shadow_buffer_lighttrispvs)
958 Mem_Free(r_shadow_buffer_lighttrispvs);
959 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
960 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
964 void R_Shadow_PrepareShadowMark(int numtris)
966 // make sure shadowmark is big enough for this volume
967 if (maxshadowmark < numtris)
969 maxshadowmark = numtris;
971 Mem_Free(shadowmark);
973 Mem_Free(shadowmarklist);
974 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
975 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
979 // if shadowmarkcount wrapped we clear the array and adjust accordingly
980 if (shadowmarkcount == 0)
983 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
988 void R_Shadow_PrepareShadowSides(int numtris)
990 if (maxshadowsides < numtris)
992 maxshadowsides = numtris;
994 Mem_Free(shadowsides);
996 Mem_Free(shadowsideslist);
997 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
998 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
1003 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)
1006 int outtriangles = 0, outvertices = 0;
1008 const float *vertex;
1009 float ratio, direction[3], projectvector[3];
1011 if (projectdirection)
1012 VectorScale(projectdirection, projectdistance, projectvector);
1014 VectorClear(projectvector);
1016 // create the vertices
1017 if (projectdirection)
1019 for (i = 0;i < numshadowmarktris;i++)
1021 element = inelement3i + shadowmarktris[i] * 3;
1022 for (j = 0;j < 3;j++)
1024 if (vertexupdate[element[j]] != vertexupdatenum)
1026 vertexupdate[element[j]] = vertexupdatenum;
1027 vertexremap[element[j]] = outvertices;
1028 vertex = invertex3f + element[j] * 3;
1029 // project one copy of the vertex according to projectvector
1030 VectorCopy(vertex, outvertex3f);
1031 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1040 for (i = 0;i < numshadowmarktris;i++)
1042 element = inelement3i + shadowmarktris[i] * 3;
1043 for (j = 0;j < 3;j++)
1045 if (vertexupdate[element[j]] != vertexupdatenum)
1047 vertexupdate[element[j]] = vertexupdatenum;
1048 vertexremap[element[j]] = outvertices;
1049 vertex = invertex3f + element[j] * 3;
1050 // project one copy of the vertex to the sphere radius of the light
1051 // (FIXME: would projecting it to the light box be better?)
1052 VectorSubtract(vertex, projectorigin, direction);
1053 ratio = projectdistance / VectorLength(direction);
1054 VectorCopy(vertex, outvertex3f);
1055 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1063 if (r_shadow_frontsidecasting.integer)
1065 for (i = 0;i < numshadowmarktris;i++)
1067 int remappedelement[3];
1069 const int *neighbortriangle;
1071 markindex = shadowmarktris[i] * 3;
1072 element = inelement3i + markindex;
1073 neighbortriangle = inneighbor3i + markindex;
1074 // output the front and back triangles
1075 outelement3i[0] = vertexremap[element[0]];
1076 outelement3i[1] = vertexremap[element[1]];
1077 outelement3i[2] = vertexremap[element[2]];
1078 outelement3i[3] = vertexremap[element[2]] + 1;
1079 outelement3i[4] = vertexremap[element[1]] + 1;
1080 outelement3i[5] = vertexremap[element[0]] + 1;
1084 // output the sides (facing outward from this triangle)
1085 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1087 remappedelement[0] = vertexremap[element[0]];
1088 remappedelement[1] = vertexremap[element[1]];
1089 outelement3i[0] = remappedelement[1];
1090 outelement3i[1] = remappedelement[0];
1091 outelement3i[2] = remappedelement[0] + 1;
1092 outelement3i[3] = remappedelement[1];
1093 outelement3i[4] = remappedelement[0] + 1;
1094 outelement3i[5] = remappedelement[1] + 1;
1099 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1101 remappedelement[1] = vertexremap[element[1]];
1102 remappedelement[2] = vertexremap[element[2]];
1103 outelement3i[0] = remappedelement[2];
1104 outelement3i[1] = remappedelement[1];
1105 outelement3i[2] = remappedelement[1] + 1;
1106 outelement3i[3] = remappedelement[2];
1107 outelement3i[4] = remappedelement[1] + 1;
1108 outelement3i[5] = remappedelement[2] + 1;
1113 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1115 remappedelement[0] = vertexremap[element[0]];
1116 remappedelement[2] = vertexremap[element[2]];
1117 outelement3i[0] = remappedelement[0];
1118 outelement3i[1] = remappedelement[2];
1119 outelement3i[2] = remappedelement[2] + 1;
1120 outelement3i[3] = remappedelement[0];
1121 outelement3i[4] = remappedelement[2] + 1;
1122 outelement3i[5] = remappedelement[0] + 1;
1131 for (i = 0;i < numshadowmarktris;i++)
1133 int remappedelement[3];
1135 const int *neighbortriangle;
1137 markindex = shadowmarktris[i] * 3;
1138 element = inelement3i + markindex;
1139 neighbortriangle = inneighbor3i + markindex;
1140 // output the front and back triangles
1141 outelement3i[0] = vertexremap[element[2]];
1142 outelement3i[1] = vertexremap[element[1]];
1143 outelement3i[2] = vertexremap[element[0]];
1144 outelement3i[3] = vertexremap[element[0]] + 1;
1145 outelement3i[4] = vertexremap[element[1]] + 1;
1146 outelement3i[5] = vertexremap[element[2]] + 1;
1150 // output the sides (facing outward from this triangle)
1151 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1153 remappedelement[0] = vertexremap[element[0]];
1154 remappedelement[1] = vertexremap[element[1]];
1155 outelement3i[0] = remappedelement[0];
1156 outelement3i[1] = remappedelement[1];
1157 outelement3i[2] = remappedelement[1] + 1;
1158 outelement3i[3] = remappedelement[0];
1159 outelement3i[4] = remappedelement[1] + 1;
1160 outelement3i[5] = remappedelement[0] + 1;
1165 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1167 remappedelement[1] = vertexremap[element[1]];
1168 remappedelement[2] = vertexremap[element[2]];
1169 outelement3i[0] = remappedelement[1];
1170 outelement3i[1] = remappedelement[2];
1171 outelement3i[2] = remappedelement[2] + 1;
1172 outelement3i[3] = remappedelement[1];
1173 outelement3i[4] = remappedelement[2] + 1;
1174 outelement3i[5] = remappedelement[1] + 1;
1179 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1181 remappedelement[0] = vertexremap[element[0]];
1182 remappedelement[2] = vertexremap[element[2]];
1183 outelement3i[0] = remappedelement[2];
1184 outelement3i[1] = remappedelement[0];
1185 outelement3i[2] = remappedelement[0] + 1;
1186 outelement3i[3] = remappedelement[2];
1187 outelement3i[4] = remappedelement[0] + 1;
1188 outelement3i[5] = remappedelement[2] + 1;
1196 *outnumvertices = outvertices;
1197 return outtriangles;
1200 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)
1203 int outtriangles = 0, outvertices = 0;
1205 const float *vertex;
1206 float ratio, direction[3], projectvector[3];
1209 if (projectdirection)
1210 VectorScale(projectdirection, projectdistance, projectvector);
1212 VectorClear(projectvector);
1214 for (i = 0;i < numshadowmarktris;i++)
1216 int remappedelement[3];
1218 const int *neighbortriangle;
1220 markindex = shadowmarktris[i] * 3;
1221 neighbortriangle = inneighbor3i + markindex;
1222 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1223 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1224 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1225 if (side[0] + side[1] + side[2] == 0)
1229 element = inelement3i + markindex;
1231 // create the vertices
1232 for (j = 0;j < 3;j++)
1234 if (side[j] + side[j+1] == 0)
1237 if (vertexupdate[k] != vertexupdatenum)
1239 vertexupdate[k] = vertexupdatenum;
1240 vertexremap[k] = outvertices;
1241 vertex = invertex3f + k * 3;
1242 VectorCopy(vertex, outvertex3f);
1243 if (projectdirection)
1245 // project one copy of the vertex according to projectvector
1246 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1250 // project one copy of the vertex to the sphere radius of the light
1251 // (FIXME: would projecting it to the light box be better?)
1252 VectorSubtract(vertex, projectorigin, direction);
1253 ratio = projectdistance / VectorLength(direction);
1254 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1261 // output the sides (facing outward from this triangle)
1264 remappedelement[0] = vertexremap[element[0]];
1265 remappedelement[1] = vertexremap[element[1]];
1266 outelement3i[0] = remappedelement[1];
1267 outelement3i[1] = remappedelement[0];
1268 outelement3i[2] = remappedelement[0] + 1;
1269 outelement3i[3] = remappedelement[1];
1270 outelement3i[4] = remappedelement[0] + 1;
1271 outelement3i[5] = remappedelement[1] + 1;
1278 remappedelement[1] = vertexremap[element[1]];
1279 remappedelement[2] = vertexremap[element[2]];
1280 outelement3i[0] = remappedelement[2];
1281 outelement3i[1] = remappedelement[1];
1282 outelement3i[2] = remappedelement[1] + 1;
1283 outelement3i[3] = remappedelement[2];
1284 outelement3i[4] = remappedelement[1] + 1;
1285 outelement3i[5] = remappedelement[2] + 1;
1292 remappedelement[0] = vertexremap[element[0]];
1293 remappedelement[2] = vertexremap[element[2]];
1294 outelement3i[0] = remappedelement[0];
1295 outelement3i[1] = remappedelement[2];
1296 outelement3i[2] = remappedelement[2] + 1;
1297 outelement3i[3] = remappedelement[0];
1298 outelement3i[4] = remappedelement[2] + 1;
1299 outelement3i[5] = remappedelement[0] + 1;
1306 *outnumvertices = outvertices;
1307 return outtriangles;
1310 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)
1316 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1318 tend = firsttriangle + numtris;
1319 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1321 // surface box entirely inside light box, no box cull
1322 if (projectdirection)
1324 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1326 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1327 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1328 shadowmarklist[numshadowmark++] = t;
1333 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1334 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1335 shadowmarklist[numshadowmark++] = t;
1340 // surface box not entirely inside light box, cull each triangle
1341 if (projectdirection)
1343 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1345 v[0] = invertex3f + e[0] * 3;
1346 v[1] = invertex3f + e[1] * 3;
1347 v[2] = invertex3f + e[2] * 3;
1348 TriangleNormal(v[0], v[1], v[2], normal);
1349 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1350 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1351 shadowmarklist[numshadowmark++] = t;
1356 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1358 v[0] = invertex3f + e[0] * 3;
1359 v[1] = invertex3f + e[1] * 3;
1360 v[2] = invertex3f + e[2] * 3;
1361 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1362 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1363 shadowmarklist[numshadowmark++] = t;
1369 static qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1374 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1376 // check if the shadow volume intersects the near plane
1378 // a ray between the eye and light origin may intersect the caster,
1379 // indicating that the shadow may touch the eye location, however we must
1380 // test the near plane (a polygon), not merely the eye location, so it is
1381 // easiest to enlarge the caster bounding shape slightly for this.
1387 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)
1389 int i, tris, outverts;
1390 if (projectdistance < 0.1)
1392 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1395 if (!numverts || !nummarktris)
1397 // make sure shadowelements is big enough for this volume
1398 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1399 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1401 if (maxvertexupdate < numverts)
1403 maxvertexupdate = numverts;
1405 Mem_Free(vertexupdate);
1407 Mem_Free(vertexremap);
1408 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1409 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1410 vertexupdatenum = 0;
1413 if (vertexupdatenum == 0)
1415 vertexupdatenum = 1;
1416 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1417 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1420 for (i = 0;i < nummarktris;i++)
1421 shadowmark[marktris[i]] = shadowmarkcount;
1423 if (r_shadow_compilingrtlight)
1425 // if we're compiling an rtlight, capture the mesh
1426 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1427 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1428 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1429 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1431 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1433 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1434 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1435 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1439 // decide which type of shadow to generate and set stencil mode
1440 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1441 // generate the sides or a solid volume, depending on type
1442 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1443 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1445 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1446 r_refdef.stats[r_stat_lights_dynamicshadowtriangles] += tris;
1447 r_refdef.stats[r_stat_lights_shadowtriangles] += tris;
1448 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1450 // increment stencil if frontface is infront of depthbuffer
1451 GL_CullFace(r_refdef.view.cullface_front);
1452 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1453 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1454 // decrement stencil if backface is infront of depthbuffer
1455 GL_CullFace(r_refdef.view.cullface_back);
1456 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1458 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1460 // decrement stencil if backface is behind depthbuffer
1461 GL_CullFace(r_refdef.view.cullface_front);
1462 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1463 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1464 // increment stencil if frontface is behind depthbuffer
1465 GL_CullFace(r_refdef.view.cullface_back);
1466 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1468 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1469 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1473 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1475 // p1, p2, p3 are in the cubemap's local coordinate system
1476 // bias = border/(size - border)
1479 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1480 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1481 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1482 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1484 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1485 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1486 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1487 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1489 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1490 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1491 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1493 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1494 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1495 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1496 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1498 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1499 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1500 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1501 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1503 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1504 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1505 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1507 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1508 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1509 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1510 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1512 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1513 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1514 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1515 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1517 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1518 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1519 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1524 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1526 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1527 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1530 VectorSubtract(maxs, mins, radius);
1531 VectorScale(radius, 0.5f, radius);
1532 VectorAdd(mins, radius, center);
1533 Matrix4x4_Transform(worldtolight, center, lightcenter);
1534 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1535 VectorSubtract(lightcenter, lightradius, pmin);
1536 VectorAdd(lightcenter, lightradius, pmax);
1538 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1539 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1540 if(ap1 > bias*an1 && ap2 > bias*an2)
1542 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1543 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1544 if(an1 > bias*ap1 && an2 > bias*ap2)
1546 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1547 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1549 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1550 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1551 if(ap1 > bias*an1 && ap2 > bias*an2)
1553 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1554 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1555 if(an1 > bias*ap1 && an2 > bias*ap2)
1557 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1558 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1560 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1561 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1562 if(ap1 > bias*an1 && ap2 > bias*an2)
1564 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1565 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1566 if(an1 > bias*ap1 && an2 > bias*ap2)
1568 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1569 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1574 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1576 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1578 // p is in the cubemap's local coordinate system
1579 // bias = border/(size - border)
1580 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1581 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1582 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1584 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1585 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1586 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1587 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1588 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1589 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1593 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1597 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1598 float scale = (size - 2*border)/size, len;
1599 float bias = border / (float)(size - border), dp, dn, ap, an;
1600 // check if cone enclosing side would cross frustum plane
1601 scale = 2 / (scale*scale + 2);
1602 Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
1603 for (i = 0;i < 5;i++)
1605 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
1607 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1608 len = scale*VectorLength2(n);
1609 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1610 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1611 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1613 if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1615 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1616 len = scale*VectorLength2(n);
1617 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1618 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1619 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1621 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1622 // check if frustum corners/origin cross plane sides
1624 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1625 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1626 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1627 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1628 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1629 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1630 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1631 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1632 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1633 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1634 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1635 for (i = 0;i < 4;i++)
1637 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1638 VectorSubtract(n, p, n);
1639 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1640 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1641 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1642 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1643 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1644 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1645 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1646 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1647 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1650 // finite version, assumes corners are a finite distance from origin dependent on far plane
1651 for (i = 0;i < 5;i++)
1653 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1654 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1655 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1656 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1657 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1658 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1659 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1660 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1661 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1662 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1665 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1668 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)
1676 int mask, surfacemask = 0;
1677 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1679 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1680 tend = firsttriangle + numtris;
1681 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1683 // surface box entirely inside light box, no box cull
1684 if (projectdirection)
1686 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1688 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1689 TriangleNormal(v[0], v[1], v[2], normal);
1690 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1692 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1693 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1694 surfacemask |= mask;
1697 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;
1698 shadowsides[numshadowsides] = mask;
1699 shadowsideslist[numshadowsides++] = t;
1706 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1708 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1709 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1711 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1712 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1713 surfacemask |= mask;
1716 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;
1717 shadowsides[numshadowsides] = mask;
1718 shadowsideslist[numshadowsides++] = t;
1726 // surface box not entirely inside light box, cull each triangle
1727 if (projectdirection)
1729 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1731 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1732 TriangleNormal(v[0], v[1], v[2], normal);
1733 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1734 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1736 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1737 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1738 surfacemask |= mask;
1741 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;
1742 shadowsides[numshadowsides] = mask;
1743 shadowsideslist[numshadowsides++] = t;
1750 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1752 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1753 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1754 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1756 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1757 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1758 surfacemask |= mask;
1761 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;
1762 shadowsides[numshadowsides] = mask;
1763 shadowsideslist[numshadowsides++] = t;
1772 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)
1774 int i, j, outtriangles = 0;
1775 int *outelement3i[6];
1776 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1778 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1779 // make sure shadowelements is big enough for this mesh
1780 if (maxshadowtriangles < outtriangles)
1781 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1783 // compute the offset and size of the separate index lists for each cubemap side
1785 for (i = 0;i < 6;i++)
1787 outelement3i[i] = shadowelements + outtriangles * 3;
1788 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1789 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1790 outtriangles += sidetotals[i];
1793 // gather up the (sparse) triangles into separate index lists for each cubemap side
1794 for (i = 0;i < numsidetris;i++)
1796 const int *element = elements + sidetris[i] * 3;
1797 for (j = 0;j < 6;j++)
1799 if (sides[i] & (1 << j))
1801 outelement3i[j][0] = element[0];
1802 outelement3i[j][1] = element[1];
1803 outelement3i[j][2] = element[2];
1804 outelement3i[j] += 3;
1809 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1812 static void R_Shadow_MakeTextures_MakeCorona(void)
1816 unsigned char pixels[32][32][4];
1817 for (y = 0;y < 32;y++)
1819 dy = (y - 15.5f) * (1.0f / 16.0f);
1820 for (x = 0;x < 32;x++)
1822 dx = (x - 15.5f) * (1.0f / 16.0f);
1823 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1824 a = bound(0, a, 255);
1825 pixels[y][x][0] = a;
1826 pixels[y][x][1] = a;
1827 pixels[y][x][2] = a;
1828 pixels[y][x][3] = 255;
1831 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, false);
1834 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1836 float dist = sqrt(x*x+y*y+z*z);
1837 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1838 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1839 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1842 static void R_Shadow_MakeTextures(void)
1845 float intensity, dist;
1847 R_Shadow_FreeShadowMaps();
1848 R_FreeTexturePool(&r_shadow_texturepool);
1849 r_shadow_texturepool = R_AllocTexturePool();
1850 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1851 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1852 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1853 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1854 for (x = 0;x <= ATTENTABLESIZE;x++)
1856 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1857 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1858 r_shadow_attentable[x] = bound(0, intensity, 1);
1860 // 1D gradient texture
1861 for (x = 0;x < ATTEN1DSIZE;x++)
1862 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1863 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1864 // 2D circle texture
1865 for (y = 0;y < ATTEN2DSIZE;y++)
1866 for (x = 0;x < ATTEN2DSIZE;x++)
1867 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);
1868 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1869 // 3D sphere texture
1870 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1872 for (z = 0;z < ATTEN3DSIZE;z++)
1873 for (y = 0;y < ATTEN3DSIZE;y++)
1874 for (x = 0;x < ATTEN3DSIZE;x++)
1875 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));
1876 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);
1879 r_shadow_attenuation3dtexture = NULL;
1882 R_Shadow_MakeTextures_MakeCorona();
1884 // Editor light sprites
1885 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1902 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1903 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1920 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1921 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1938 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1939 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1956 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1957 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1974 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1975 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1992 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1995 void R_Shadow_ValidateCvars(void)
1997 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1998 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1999 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
2000 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
2001 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
2002 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
2005 void R_Shadow_RenderMode_Begin(void)
2011 R_Shadow_ValidateCvars();
2013 if (!r_shadow_attenuation2dtexture
2014 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
2015 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
2016 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
2017 R_Shadow_MakeTextures();
2020 R_Mesh_ResetTextureState();
2021 GL_BlendFunc(GL_ONE, GL_ZERO);
2022 GL_DepthRange(0, 1);
2023 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
2025 GL_DepthMask(false);
2026 GL_Color(0, 0, 0, 1);
2027 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2029 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2031 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
2033 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
2034 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
2036 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
2038 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
2039 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
2043 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
2044 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
2047 switch(vid.renderpath)
2049 case RENDERPATH_GL20:
2050 case RENDERPATH_D3D9:
2051 case RENDERPATH_D3D10:
2052 case RENDERPATH_D3D11:
2053 case RENDERPATH_SOFT:
2054 case RENDERPATH_GLES2:
2055 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
2057 case RENDERPATH_GL11:
2058 case RENDERPATH_GL13:
2059 case RENDERPATH_GLES1:
2060 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
2061 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
2062 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
2063 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
2064 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
2065 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
2067 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
2073 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
2074 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
2075 r_shadow_drawbuffer = drawbuffer;
2076 r_shadow_readbuffer = readbuffer;
2078 r_shadow_cullface_front = r_refdef.view.cullface_front;
2079 r_shadow_cullface_back = r_refdef.view.cullface_back;
2082 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
2084 rsurface.rtlight = rtlight;
2087 void R_Shadow_RenderMode_Reset(void)
2089 R_Mesh_ResetTextureState();
2090 R_Mesh_SetRenderTargets(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture, NULL, NULL, NULL);
2091 R_SetViewport(&r_refdef.view.viewport);
2092 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
2093 GL_DepthRange(0, 1);
2095 GL_DepthMask(false);
2096 GL_DepthFunc(GL_LEQUAL);
2097 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2098 r_refdef.view.cullface_front = r_shadow_cullface_front;
2099 r_refdef.view.cullface_back = r_shadow_cullface_back;
2100 GL_CullFace(r_refdef.view.cullface_back);
2101 GL_Color(1, 1, 1, 1);
2102 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2103 GL_BlendFunc(GL_ONE, GL_ZERO);
2104 R_SetupShader_Generic_NoTexture(false, false);
2105 r_shadow_usingshadowmap2d = false;
2106 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2109 void R_Shadow_ClearStencil(void)
2111 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2112 r_refdef.stats[r_stat_lights_clears]++;
2115 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2117 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2118 if (r_shadow_rendermode == mode)
2120 R_Shadow_RenderMode_Reset();
2121 GL_DepthFunc(GL_LESS);
2122 GL_ColorMask(0, 0, 0, 0);
2123 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2124 GL_CullFace(GL_NONE);
2125 R_SetupShader_DepthOrShadow(false, false, false); // FIXME test if we have a skeletal model?
2126 r_shadow_rendermode = mode;
2131 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2132 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2133 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2135 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2136 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2137 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2142 static void R_Shadow_MakeVSDCT(void)
2144 // maps to a 2x3 texture rectangle with normalized coordinates
2149 // stores abs(dir.xy), offset.xy/2.5
2150 unsigned char data[4*6] =
2152 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2153 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2154 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2155 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2156 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2157 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2159 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2162 static void R_Shadow_MakeShadowMap(int texturesize)
2164 switch (r_shadow_shadowmode)
2166 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2167 if (r_shadow_shadowmap2ddepthtexture) return;
2168 if (r_fb.usedepthtextures)
2170 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);
2171 r_shadow_shadowmap2ddepthbuffer = NULL;
2172 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2176 r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", texturesize, texturesize, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2177 r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
2178 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2186 void R_Shadow_ClearShadowMapTexture(void)
2188 r_viewport_t viewport;
2189 float clearcolor[4];
2191 // if they don't exist, create our textures now
2192 if (!r_shadow_shadowmap2ddepthtexture)
2193 R_Shadow_MakeShadowMap(r_shadow_shadowmaptexturesize);
2194 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2195 R_Shadow_MakeVSDCT();
2197 // we're setting up to render shadowmaps, so change rendermode
2198 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2200 R_Mesh_ResetTextureState();
2201 R_Shadow_RenderMode_Reset();
2202 if (r_shadow_shadowmap2ddepthbuffer)
2203 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2205 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2206 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2207 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2211 // we have to set a viewport to clear anything in some renderpaths (D3D)
2212 R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize, 0, 0, 1.0, 1.0, 0.001f, 1.0f, NULL);
2213 R_SetViewport(&viewport);
2214 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2215 if (r_shadow_shadowmap2ddepthbuffer)
2216 GL_ColorMask(1, 1, 1, 1);
2218 GL_ColorMask(0, 0, 0, 0);
2219 switch (vid.renderpath)
2221 case RENDERPATH_GL11:
2222 case RENDERPATH_GL13:
2223 case RENDERPATH_GL20:
2224 case RENDERPATH_SOFT:
2225 case RENDERPATH_GLES1:
2226 case RENDERPATH_GLES2:
2227 GL_CullFace(r_refdef.view.cullface_back);
2229 case RENDERPATH_D3D9:
2230 case RENDERPATH_D3D10:
2231 case RENDERPATH_D3D11:
2232 // we invert the cull mode because we flip the projection matrix
2233 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2234 GL_CullFace(r_refdef.view.cullface_front);
2237 Vector4Set(clearcolor, 1, 1, 1, 1);
2238 if (r_shadow_shadowmap2ddepthbuffer)
2239 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2241 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2244 static void R_Shadow_SetShadowmapParametersForLight(qboolean noselfshadowpass)
2246 int size = rsurface.rtlight->shadowmapatlassidesize;
2247 float nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2248 float farclip = 1.0f;
2249 float bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2250 r_shadow_lightshadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
2251 r_shadow_lightshadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
2252 r_shadow_lightshadowmap_texturescale[2] = rsurface.rtlight->shadowmapatlasposition[0] + (noselfshadowpass ? size * 2 : 0);
2253 r_shadow_lightshadowmap_texturescale[3] = rsurface.rtlight->shadowmapatlasposition[1];
2254 r_shadow_lightshadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2255 r_shadow_lightshadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2256 r_shadow_lightshadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2257 r_shadow_lightshadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2258 if (r_shadow_shadowmap2ddepthbuffer)
2260 // completely different meaning than in depthtexture approach
2261 r_shadow_lightshadowmap_parameters[1] = 0;
2262 r_shadow_lightshadowmap_parameters[3] = -bias;
2266 static void R_Shadow_RenderMode_ShadowMap(int side, int size, int x, int y)
2268 float nearclip, farclip, bias;
2269 r_viewport_t viewport;
2271 float clearcolor[4];
2273 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_SHADOWMAP2D)
2275 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2277 R_Mesh_ResetTextureState();
2278 R_Shadow_RenderMode_Reset();
2279 if (r_shadow_shadowmap2ddepthbuffer)
2280 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2282 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2283 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2284 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2289 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2291 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2293 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
2294 R_SetViewport(&viewport);
2295 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2296 flipped = (side & 1) ^ (side >> 2);
2297 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2298 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2300 Vector4Set(clearcolor, 1,1,1,1);
2301 if (r_shadow_shadowmap2ddepthbuffer)
2302 GL_ColorMask(1,1,1,1);
2304 GL_ColorMask(0,0,0,0);
2305 switch(vid.renderpath)
2307 case RENDERPATH_GL11:
2308 case RENDERPATH_GL13:
2309 case RENDERPATH_GL20:
2310 case RENDERPATH_SOFT:
2311 case RENDERPATH_GLES1:
2312 case RENDERPATH_GLES2:
2313 GL_CullFace(r_refdef.view.cullface_back);
2315 case RENDERPATH_D3D9:
2316 case RENDERPATH_D3D10:
2317 case RENDERPATH_D3D11:
2318 // we invert the cull mode because we flip the projection matrix
2319 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2320 GL_CullFace(r_refdef.view.cullface_front);
2324 // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
2325 r_shadow_shadowmapside = side;
2328 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass)
2330 R_Mesh_ResetTextureState();
2333 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2334 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2335 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2336 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2339 R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
2340 R_Shadow_RenderMode_Reset();
2341 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2343 GL_DepthFunc(GL_EQUAL);
2344 // do global setup needed for the chosen lighting mode
2345 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2346 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2347 r_shadow_usingshadowmap2d = shadowmapping;
2348 r_shadow_rendermode = r_shadow_lightingrendermode;
2349 // only draw light where this geometry was already rendered AND the
2350 // stencil is 128 (values other than this mean shadow)
2352 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2354 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2357 static const unsigned short bboxelements[36] =
2367 static const float bboxpoints[8][3] =
2379 void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping)
2382 float vertex3f[8*3];
2383 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2384 // do global setup needed for the chosen lighting mode
2385 R_Shadow_RenderMode_Reset();
2386 r_shadow_rendermode = r_shadow_lightingrendermode;
2387 R_EntityMatrix(&identitymatrix);
2388 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2389 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2390 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
2391 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2393 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
2395 r_shadow_usingshadowmap2d = shadowmapping;
2397 // render the lighting
2398 R_SetupShader_DeferredLight(rsurface.rtlight);
2399 for (i = 0;i < 8;i++)
2400 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2401 GL_ColorMask(1,1,1,1);
2402 GL_DepthMask(false);
2403 GL_DepthRange(0, 1);
2404 GL_PolygonOffset(0, 0);
2406 GL_DepthFunc(GL_GREATER);
2407 GL_CullFace(r_refdef.view.cullface_back);
2408 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
2409 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2412 #define MAXBOUNCEGRIDSPLATSIZE 7
2413 #define MAXBOUNCEGRIDSPLATSIZE1 (MAXBOUNCEGRIDSPLATSIZE+1)
2415 // these are temporary data per-frame, sorted and performed in a more
2416 // cache-friendly order than the original photons
2417 typedef struct r_shadow_bouncegrid_splatpath_s
2423 vec_t splatintensity;
2424 int remainingsplats;
2426 r_shadow_bouncegrid_splatpath_t;
2428 static void R_Shadow_BounceGrid_AddSplatPath(vec3_t originalstart, vec3_t originalend, vec3_t color)
2438 r_shadow_bouncegrid_splatpath_t *path;
2440 // cull paths that fail R_CullBox in dynamic mode
2441 if (!r_shadow_bouncegrid_state.settings.staticmode
2442 && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
2444 vec3_t cullmins, cullmaxs;
2445 cullmins[0] = min(originalstart[0], originalend[0]) - r_shadow_bouncegrid_state.settings.spacing[0];
2446 cullmins[1] = min(originalstart[1], originalend[1]) - r_shadow_bouncegrid_state.settings.spacing[1];
2447 cullmins[2] = min(originalstart[2], originalend[2]) - r_shadow_bouncegrid_state.settings.spacing[2];
2448 cullmaxs[0] = max(originalstart[0], originalend[0]) + r_shadow_bouncegrid_state.settings.spacing[0];
2449 cullmaxs[1] = max(originalstart[1], originalend[1]) + r_shadow_bouncegrid_state.settings.spacing[1];
2450 cullmaxs[2] = max(originalstart[2], originalend[2]) + r_shadow_bouncegrid_state.settings.spacing[2];
2451 if (R_CullBox(cullmins, cullmaxs))
2455 // if the light path is going upward, reverse it - we always draw down.
2456 if (originalend[2] < originalstart[2])
2458 VectorCopy(originalend, start);
2459 VectorCopy(originalstart, end);
2463 VectorCopy(originalstart, start);
2464 VectorCopy(originalend, end);
2467 // transform to texture pixels
2468 start[0] = (start[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2469 start[1] = (start[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2470 start[2] = (start[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2471 end[0] = (end[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2472 end[1] = (end[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2473 end[2] = (end[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2475 // check if we need to grow the splatpaths array
2476 if (r_shadow_bouncegrid_state.maxsplatpaths <= r_shadow_bouncegrid_state.numsplatpaths)
2478 // double the limit, this will persist from frame to frame so we don't
2479 // make the same mistake each time
2480 r_shadow_bouncegrid_state.maxsplatpaths *= 2;
2481 if (r_shadow_bouncegrid_state.maxsplatpaths < 16384)
2482 r_shadow_bouncegrid_state.maxsplatpaths = 16384;
2483 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);
2486 // divide a series of splats along the length using the maximum axis
2487 VectorSubtract(end, start, diff);
2488 // pick the best axis to trace along
2490 if (diff[1]*diff[1] > diff[bestaxis]*diff[bestaxis])
2492 if (diff[2]*diff[2] > diff[bestaxis]*diff[bestaxis])
2494 len = fabs(diff[bestaxis]);
2496 numsplats = (int)(floor(len + 0.5f));
2498 numsplats = bound(0, numsplats, 1024);
2500 VectorSubtract(originalstart, originalend, originaldir);
2501 VectorNormalize(originaldir);
2503 path = r_shadow_bouncegrid_state.splatpaths + r_shadow_bouncegrid_state.numsplatpaths++;
2504 VectorCopy(start, path->point);
2505 VectorScale(diff, ilen, path->step);
2506 VectorCopy(color, path->splatcolor);
2507 VectorCopy(originaldir, path->splatdir);
2508 path->splatintensity = VectorLength(color);
2509 path->remainingsplats = numsplats;
2512 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
2514 qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
2521 // see if there are really any lights to render...
2522 if (enable && r_shadow_bouncegrid_static.integer)
2525 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2526 for (lightindex = 0;lightindex < range;lightindex++)
2528 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2529 if (!light || !(light->flags & flag))
2531 rtlight = &light->rtlight;
2532 // when static, we skip styled lights because they tend to change...
2533 if (rtlight->style > 0)
2535 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
2536 if (!VectorLength2(lightcolor))
2546 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
2548 qboolean s = r_shadow_bouncegrid_static.integer != 0;
2549 float spacing = s ? r_shadow_bouncegrid_static_spacing.value : r_shadow_bouncegrid_dynamic_spacing.value;
2551 // prevent any garbage in alignment padded areas as we'll be using memcmp
2552 memset(settings, 0, sizeof(*settings));
2554 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
2555 settings->staticmode = s;
2556 settings->blur = r_shadow_bouncegrid_blur.integer != 0;
2557 settings->floatcolors = bound(0, r_shadow_bouncegrid_floatcolors.integer, 2);
2558 settings->lightpathsize = bound(1, r_shadow_bouncegrid_lightpathsize.integer, MAXBOUNCEGRIDSPLATSIZE);
2559 settings->bounceanglediffuse = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
2560 settings->directionalshading = (s ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_dynamic_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
2561 settings->dlightparticlemultiplier = s ? 0 : r_shadow_bouncegrid_dynamic_dlightparticlemultiplier.value;
2562 settings->hitmodels = s ? false : r_shadow_bouncegrid_dynamic_hitmodels.integer != 0;
2563 settings->includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
2564 settings->lightradiusscale = (s ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_dynamic_lightradiusscale.value);
2565 settings->maxbounce = (s ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_dynamic_maxbounce.integer);
2566 settings->particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
2567 settings->particleintensity = r_shadow_bouncegrid_particleintensity.value * 16384.0f * (settings->directionalshading ? 4.0f : 1.0f) / (spacing * spacing);
2568 settings->maxphotons = s ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_dynamic_maxphotons.integer;
2569 settings->energyperphoton = s ? r_shadow_bouncegrid_static_energyperphoton.integer : r_shadow_bouncegrid_dynamic_energyperphoton.integer;
2570 settings->spacing[0] = spacing;
2571 settings->spacing[1] = spacing;
2572 settings->spacing[2] = spacing;
2573 settings->stablerandom = s ? 1 : r_shadow_bouncegrid_dynamic_stablerandom.integer;
2575 // bound the values for sanity
2576 settings->maxphotons = bound(1, settings->maxphotons, 25000000);
2577 settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
2578 settings->maxbounce = bound(0, settings->maxbounce, 16);
2579 settings->spacing[0] = bound(1, settings->spacing[0], 512);
2580 settings->spacing[1] = bound(1, settings->spacing[1], 512);
2581 settings->spacing[2] = bound(1, settings->spacing[2], 512);
2583 // check if the ram requirements for blur would be excessive and disable it (increase lightpathsize to compensate)
2584 if (spacing < 32 && settings->blur)
2586 settings->blur = false;
2587 settings->lightpathsize += 2;
2591 static void R_Shadow_BounceGrid_UpdateSpacing(void)
2602 r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
2604 // get the spacing values
2605 spacing[0] = settings->spacing[0];
2606 spacing[1] = settings->spacing[1];
2607 spacing[2] = settings->spacing[2];
2608 ispacing[0] = 1.0f / spacing[0];
2609 ispacing[1] = 1.0f / spacing[1];
2610 ispacing[2] = 1.0f / spacing[2];
2612 // calculate texture size enclosing entire world bounds at the spacing
2613 if (r_refdef.scene.worldmodel)
2615 VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
2616 VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
2620 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
2621 VectorSet(maxs, 1048576.0f, 1048576.0f, 1048576.0f);
2623 VectorSubtract(maxs, mins, size);
2624 // now we can calculate the resolution we want
2625 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2626 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2627 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2628 // figure out the exact texture size (honoring power of 2 if required)
2629 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2630 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2631 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2632 if (vid.support.arb_texture_non_power_of_two)
2634 resolution[0] = c[0];
2635 resolution[1] = c[1];
2636 resolution[2] = c[2];
2640 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2641 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2642 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2644 size[0] = spacing[0] * resolution[0];
2645 size[1] = spacing[1] * resolution[1];
2646 size[2] = spacing[2] * resolution[2];
2648 // if dynamic we may or may not want to use the world bounds
2649 // if the dynamic size is smaller than the world bounds, use it instead
2650 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]))
2652 // we know the resolution we want
2653 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
2654 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
2655 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
2656 // now we can calculate the texture size (power of 2 if required)
2657 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2658 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2659 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2660 if (vid.support.arb_texture_non_power_of_two)
2662 resolution[0] = c[0];
2663 resolution[1] = c[1];
2664 resolution[2] = c[2];
2668 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2669 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2670 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2672 size[0] = spacing[0] * resolution[0];
2673 size[1] = spacing[1] * resolution[1];
2674 size[2] = spacing[2] * resolution[2];
2675 // center the rendering on the view
2676 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2677 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2678 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2681 // recalculate the maxs in case the resolution was not satisfactory
2682 VectorAdd(mins, size, maxs);
2684 // check if this changed the texture size
2685 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);
2686 r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
2687 VectorCopy(mins, r_shadow_bouncegrid_state.mins);
2688 VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
2689 VectorCopy(size, r_shadow_bouncegrid_state.size);
2690 VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
2691 VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
2692 VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
2694 // reallocate pixels for this update if needed...
2695 r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
2696 r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
2697 r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
2698 numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
2699 if (r_shadow_bouncegrid_state.numpixels != numpixels)
2701 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
2702 r_shadow_bouncegrid_state.highpixels = NULL;
2703 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2704 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2705 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2706 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2707 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2708 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2709 r_shadow_bouncegrid_state.numpixels = numpixels;
2712 // update the bouncegrid matrix to put it in the world properly
2713 memset(m, 0, sizeof(m));
2714 m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
2715 m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
2716 m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
2717 m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
2718 m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
2719 m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
2721 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
2724 #define MAXBOUNCEGRIDPARTICLESPERLIGHT 1048576
2726 // enumerate world rtlights and sum the overall amount of light in the world,
2727 // from that we can calculate a scaling factor to fairly distribute photons
2728 // to all the lights
2730 // this modifies rtlight->photoncolor and rtlight->photons
2731 static void R_Shadow_BounceGrid_AssignPhotons(r_shadow_bouncegrid_settings_t *settings, unsigned int range, unsigned int range1, unsigned int range2, int flag, float *photonscaling)
2733 float normalphotonscaling;
2734 float maxphotonscaling;
2735 float photoncount = 0.0f;
2736 float lightintensity;
2742 unsigned int lightindex;
2745 for (lightindex = 0;lightindex < range2;lightindex++)
2747 if (lightindex < range)
2749 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2752 rtlight = &light->rtlight;
2753 VectorClear(rtlight->photoncolor);
2754 rtlight->photons = 0;
2755 if (!(light->flags & flag))
2757 if (settings->staticmode)
2759 // when static, we skip styled lights because they tend to change...
2760 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2766 rtlight = r_refdef.scene.lights[lightindex - range];
2767 VectorClear(rtlight->photoncolor);
2768 rtlight->photons = 0;
2770 // draw only visible lights (major speedup)
2771 radius = rtlight->radius * settings->lightradiusscale;
2772 cullmins[0] = rtlight->shadoworigin[0] - radius;
2773 cullmins[1] = rtlight->shadoworigin[1] - radius;
2774 cullmins[2] = rtlight->shadoworigin[2] - radius;
2775 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2776 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2777 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2778 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2779 if (!settings->staticmode)
2781 if (R_CullBox(cullmins, cullmaxs))
2783 if (r_refdef.scene.worldmodel
2784 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2785 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2787 if (w * VectorLength2(rtlight->color) == 0.0f)
2790 // a light that does not emit any light before style is applied, can be
2791 // skipped entirely (it may just be a corona)
2792 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2794 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2795 VectorScale(rtlight->color, w, rtlight->photoncolor);
2796 // skip lights that will emit no photons
2797 if (!VectorLength2(rtlight->photoncolor))
2799 // shoot particles from this light
2800 // use a calculation for the number of particles that will not
2801 // vary with lightstyle, otherwise we get randomized particle
2802 // distribution, the seeded random is only consistent for a
2803 // consistent number of particles on this light...
2804 s = rtlight->radius;
2805 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2806 if (lightindex >= range)
2807 lightintensity *= settings->dlightparticlemultiplier;
2808 rtlight->photons = bound(0.0f, lightintensity * s * s, MAXBOUNCEGRIDPARTICLESPERLIGHT);
2809 photoncount += rtlight->photons;
2810 // if the lightstyle happens to be off right now, we can skip actually
2811 // firing the photons, but we did have to count them in the total.
2812 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2813 // rtlight->photons = 0;
2815 // the user provided an energyperphoton value which we try to use
2816 // if that results in too many photons to shoot this frame, then we cap it
2817 // which causes photons to appear/disappear from frame to frame, so we don't
2818 // like doing that in the typical case
2819 normalphotonscaling = 1.0f / max(0.0001f, settings->energyperphoton);
2820 maxphotonscaling = (float)settings->maxphotons / max(1, photoncount);
2821 *photonscaling = min(normalphotonscaling, maxphotonscaling);
2824 static int R_Shadow_BounceGrid_SplatPathCompare(const void *pa, const void *pb)
2826 r_shadow_bouncegrid_splatpath_t *a = (r_shadow_bouncegrid_splatpath_t *)pa;
2827 r_shadow_bouncegrid_splatpath_t *b = (r_shadow_bouncegrid_splatpath_t *)pb;
2828 // we only really care about sorting by Z
2829 if (a->point[2] < b->point[2])
2831 if (a->point[2] > b->point[2])
2836 static void R_Shadow_BounceGrid_ClearPixels(void)
2838 // clear the highpixels array we'll be accumulating into
2839 if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2840 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2841 if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2842 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2843 r_shadow_bouncegrid_state.highpixels_index = 0;
2844 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2845 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2848 static void R_Shadow_BounceGrid_PerformSplats(void)
2850 int splatsize = r_shadow_bouncegrid_state.settings.lightpathsize;
2851 int splatsize1 = splatsize + 1;
2852 r_shadow_bouncegrid_splatpath_t *splatpaths = r_shadow_bouncegrid_state.splatpaths;
2853 r_shadow_bouncegrid_splatpath_t *splatpath;
2854 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2855 int numsplatpaths = r_shadow_bouncegrid_state.numsplatpaths;
2861 float texlerp[MAXBOUNCEGRIDSPLATSIZE1][3];
2862 float splatcolor[32];
2863 float boxweight = 1.0f / (splatsize * splatsize * splatsize);
2866 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2867 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2871 // hush warnings about uninitialized data - pixelbands doesn't change but...
2872 memset(splatcolor, 0, sizeof(splatcolor));
2874 // we use this a lot, so get a local copy
2875 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2877 // sort the splats before we execute them, to reduce cache misses
2878 if (r_shadow_bouncegrid_sortlightpaths.integer)
2879 qsort(splatpaths, numsplatpaths, sizeof(*splatpaths), R_Shadow_BounceGrid_SplatPathCompare);
2881 // the middle row/column/layer of each splat are full intensity
2882 for (step = 1;step < splatsize;step++)
2883 VectorSet(texlerp[step], 1.0f, 1.0f, 1.0f);
2885 splatpath = splatpaths;
2886 for (splatindex = 0;splatindex < numsplatpaths;splatindex++, splatpath++)
2888 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2889 // accumulate average shotcolor
2890 VectorCopy(splatpath->splatdir, dir);
2891 splatcolor[ 0] = splatpath->splatcolor[0];
2892 splatcolor[ 1] = splatpath->splatcolor[1];
2893 splatcolor[ 2] = splatpath->splatcolor[2];
2894 splatcolor[ 3] = 0.0f;
2897 // store bentnormal in case the shader has a use for it,
2898 // bentnormal is an intensity-weighted average of the directions,
2899 // and will be normalized on conversion to texture pixels.
2900 splatcolor[ 4] = dir[0] * splatpath->splatintensity;
2901 splatcolor[ 5] = dir[1] * splatpath->splatintensity;
2902 splatcolor[ 6] = dir[2] * splatpath->splatintensity;
2903 splatcolor[ 7] = splatpath->splatintensity;
2904 // for each color component (R, G, B) calculate the amount that a
2905 // direction contributes
2906 splatcolor[ 8] = splatcolor[0] * max(0.0f, dir[0]);
2907 splatcolor[ 9] = splatcolor[0] * max(0.0f, dir[1]);
2908 splatcolor[10] = splatcolor[0] * max(0.0f, dir[2]);
2909 splatcolor[11] = 0.0f;
2910 splatcolor[12] = splatcolor[1] * max(0.0f, dir[0]);
2911 splatcolor[13] = splatcolor[1] * max(0.0f, dir[1]);
2912 splatcolor[14] = splatcolor[1] * max(0.0f, dir[2]);
2913 splatcolor[15] = 0.0f;
2914 splatcolor[16] = splatcolor[2] * max(0.0f, dir[0]);
2915 splatcolor[17] = splatcolor[2] * max(0.0f, dir[1]);
2916 splatcolor[18] = splatcolor[2] * max(0.0f, dir[2]);
2917 splatcolor[19] = 0.0f;
2918 // and do the same for negative directions
2919 splatcolor[20] = splatcolor[0] * max(0.0f, -dir[0]);
2920 splatcolor[21] = splatcolor[0] * max(0.0f, -dir[1]);
2921 splatcolor[22] = splatcolor[0] * max(0.0f, -dir[2]);
2922 splatcolor[23] = 0.0f;
2923 splatcolor[24] = splatcolor[1] * max(0.0f, -dir[0]);
2924 splatcolor[25] = splatcolor[1] * max(0.0f, -dir[1]);
2925 splatcolor[26] = splatcolor[1] * max(0.0f, -dir[2]);
2926 splatcolor[27] = 0.0f;
2927 splatcolor[28] = splatcolor[2] * max(0.0f, -dir[0]);
2928 splatcolor[29] = splatcolor[2] * max(0.0f, -dir[1]);
2929 splatcolor[30] = splatcolor[2] * max(0.0f, -dir[2]);
2930 splatcolor[31] = 0.0f;
2932 // calculate the number of steps we need to traverse this distance
2933 VectorCopy(splatpath->point, steppos);
2934 VectorCopy(splatpath->step, stepdelta);
2935 numsteps = splatpath->remainingsplats;
2936 for (step = 0;step < numsteps;step++)
2938 r_refdef.stats[r_stat_bouncegrid_splats]++;
2939 // figure out the min corner of the pixels we'll need to update
2940 texcorner[0] = steppos[0] - (splatsize1 * 0.5f);
2941 texcorner[1] = steppos[1] - (splatsize1 * 0.5f);
2942 texcorner[2] = steppos[2] - (splatsize1 * 0.5f);
2943 tex[0] = (int)floor(texcorner[0]);
2944 tex[1] = (int)floor(texcorner[1]);
2945 tex[2] = (int)floor(texcorner[2]);
2946 // only update if it is within reasonable bounds
2950 && tex[0] < resolution[0] - splatsize1
2951 && tex[1] < resolution[1] - splatsize1
2952 && tex[2] < resolution[2] - splatsize1)
2954 // it is within bounds... do the real work now
2957 // calculate the antialiased box edges
2958 texlerp[splatsize][0] = texcorner[0] - tex[0];
2959 texlerp[splatsize][1] = texcorner[1] - tex[1];
2960 texlerp[splatsize][2] = texcorner[2] - tex[2];
2961 texlerp[0][0] = 1.0f - texlerp[splatsize][0];
2962 texlerp[0][1] = 1.0f - texlerp[splatsize][1];
2963 texlerp[0][2] = 1.0f - texlerp[splatsize][2];
2965 // accumulate light onto the pixels
2966 for (zi = 0;zi < splatsize1;zi++)
2968 for (yi = 0;yi < splatsize1;yi++)
2970 int index = ((tex[2]+zi)*resolution[1]+tex[1]+yi)*resolution[0]+tex[0];
2971 for (xi = 0;xi < splatsize1;xi++, index++)
2973 float w = texlerp[xi][0]*texlerp[yi][1]*texlerp[zi][2] * boxweight;
2975 float *p = highpixels + 4 * index + band * pixelsperband * 4;
2976 for (;band < pixelbands;band++, p += pixelsperband * 4)
2978 // add to the pixel color
2979 p[0] += splatcolor[band*4+0] * w;
2980 p[1] += splatcolor[band*4+1] * w;
2981 p[2] += splatcolor[band*4+2] * w;
2982 p[3] += splatcolor[band*4+3] * w;
2988 VectorAdd(steppos, stepdelta, steppos);
2993 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
2995 const float *inpixel;
2997 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
3000 unsigned int x, y, z;
3001 unsigned int resolution[3];
3002 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3003 for (pixelband = 0;pixelband < pixelbands;pixelband++)
3005 for (z = 1;z < resolution[2]-1;z++)
3007 for (y = 1;y < resolution[1]-1;y++)
3010 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3011 inpixel = inpixels + 4*index;
3012 outpixel = outpixels + 4*index;
3013 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
3015 outpixel[0] = (inpixel[0] + inpixel[ off] + inpixel[0-off]) * (1.0f / 3.0);
3016 outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
3017 outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
3018 outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
3025 static void R_Shadow_BounceGrid_BlurPixels(void)
3028 unsigned int resolution[3];
3030 if (!r_shadow_bouncegrid_state.settings.blur)
3033 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3035 pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3036 pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
3037 pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3038 pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
3041 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
3043 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
3045 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
3047 // toggle the state, highpixels now points to pixels[3] result
3048 r_shadow_bouncegrid_state.highpixels_index ^= 1;
3049 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3052 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
3054 int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
3055 unsigned char *pixelsbgra8 = NULL;
3056 unsigned char *pixelbgra8;
3057 unsigned short *pixelsrgba16f = NULL;
3058 unsigned short *pixelrgba16f;
3059 float *pixelsrgba32f = NULL;
3060 float *highpixels = r_shadow_bouncegrid_state.highpixels;
3063 unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
3064 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
3065 unsigned int pixelband;
3066 unsigned int x, y, z;
3067 unsigned int index, bandindex;
3068 unsigned int resolution[3];
3070 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3072 if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
3074 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3075 r_shadow_bouncegrid_state.texture = NULL;
3078 // if bentnormals exist, we need to normalize and bias them for the shader
3082 for (z = 0;z < resolution[2]-1;z++)
3084 for (y = 0;y < resolution[1]-1;y++)
3087 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3088 highpixel = highpixels + 4*index;
3089 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3091 // only convert pixels that were hit by photons
3092 if (highpixel[3] != 0.0f)
3093 VectorNormalize(highpixel);
3094 VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
3095 highpixel[pixelsperband * 4 + 3] = 1.0f;
3101 // start by clearing the pixels array - we won't be writing to all of it
3103 // then process only the pixels that have at least some color, skipping
3104 // the higher bands for speed on pixels that are black
3105 switch (floatcolors)
3108 if (r_shadow_bouncegrid_state.u8pixels == NULL)
3109 r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
3110 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
3111 for (pixelband = 0;pixelband < pixelbands;pixelband++)
3114 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
3116 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
3118 for (z = 1;z < resolution[2]-1;z++)
3120 for (y = 1;y < resolution[1]-1;y++)
3124 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3125 highpixel = highpixels + 4*index;
3126 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3128 // only convert pixels that were hit by photons
3129 if (VectorLength2(highpixel))
3131 // normalize the bentnormal now
3134 VectorNormalize(highpixel + pixelsperband * 4);
3135 highpixel[pixelsperband * 4 + 3] = 1.0f;
3137 // process all of the pixelbands for this pixel
3138 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3140 pixelbgra8 = pixelsbgra8 + 4*bandindex;
3141 bandpixel = highpixels + 4*bandindex;
3142 c[0] = (int)(bandpixel[0]*256.0f);
3143 c[1] = (int)(bandpixel[1]*256.0f);
3144 c[2] = (int)(bandpixel[2]*256.0f);
3145 c[3] = (int)(bandpixel[3]*256.0f);
3146 pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
3147 pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
3148 pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
3149 pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
3156 if (!r_shadow_bouncegrid_state.createtexture)
3157 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3159 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);
3162 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
3163 r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3164 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
3165 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3166 for (z = 1;z < resolution[2]-1;z++)
3168 for (y = 1;y < resolution[1]-1;y++)
3172 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3173 highpixel = highpixels + 4*index;
3174 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3176 // only convert pixels that were hit by photons
3177 if (VectorLength2(highpixel))
3179 // process all of the pixelbands for this pixel
3180 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3182 // time to have fun with IEEE 754 bit hacking...
3185 unsigned int raw[4];
3187 pixelrgba16f = pixelsrgba16f + 4*bandindex;
3188 bandpixel = highpixels + 4*bandindex;
3189 VectorCopy4(bandpixel, u.f);
3190 VectorCopy4(u.raw, c);
3191 // this math supports negative numbers, snaps denormals to zero
3192 //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
3193 //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
3194 //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
3195 //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
3196 // this math does not support negative
3197 pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
3198 pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
3199 pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
3200 pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
3207 if (!r_shadow_bouncegrid_state.createtexture)
3208 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3210 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);
3213 // our native format happens to match, so this is easy.
3214 pixelsrgba32f = highpixels;
3216 if (!r_shadow_bouncegrid_state.createtexture)
3217 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3219 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);
3223 r_shadow_bouncegrid_state.lastupdatetime = realtime;
3226 static void R_Shadow_BounceGrid_TracePhotons(r_shadow_bouncegrid_settings_t settings, unsigned int range, unsigned int range1, unsigned int range2, float photonscaling, int flag)
3228 vec3_t bouncerandom[10];
3231 int hitsupercontentsmask;
3232 int skipsupercontentsmask;
3237 //trace_t cliptrace2;
3238 //trace_t cliptrace3;
3239 unsigned int lightindex;
3240 unsigned int seed = (unsigned int)(realtime * 1000.0f);
3241 randomseed_t randomseed;
3243 vec3_t baseshotcolor;
3252 Math_RandomSeed_FromInt(&randomseed, seed);
3254 r_shadow_bouncegrid_state.numsplatpaths = 0;
3256 // figure out what we want to interact with
3257 if (settings.hitmodels)
3258 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;// | SUPERCONTENTS_LIQUIDSMASK;
3260 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
3261 skipsupercontentsmask = SUPERCONTENTS_SKY; // this allows the e1m5 sky shadow to work by ignoring the sky surfaces
3262 maxbounce = settings.maxbounce;
3264 for (lightindex = 0;lightindex < range2;lightindex++)
3266 if (lightindex < range)
3268 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3271 rtlight = &light->rtlight;
3274 rtlight = r_refdef.scene.lights[lightindex - range];
3275 // note that this code used to keep track of residual photons and
3276 // distribute them evenly to achieve exactly a desired photon count,
3277 // but that caused unwanted flickering in dynamic mode
3278 shootparticles = (int)floor(rtlight->photons * photonscaling);
3279 // skip if we won't be shooting any photons
3280 if (!shootparticles)
3282 radius = rtlight->radius * settings.lightradiusscale;
3283 s = settings.particleintensity / shootparticles;
3284 VectorScale(rtlight->photoncolor, s, baseshotcolor);
3285 r_refdef.stats[r_stat_bouncegrid_lights]++;
3286 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
3287 switch (settings.stablerandom)
3292 Math_RandomSeed_FromInt(&randomseed, lightindex * 11937);
3293 // prime the random number generator a bit
3294 Math_crandomf(&randomseed);
3297 seed = lightindex * 11937;
3298 // prime the random number generator a bit
3302 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
3304 VectorCopy(baseshotcolor, shotcolor);
3305 VectorCopy(rtlight->shadoworigin, clipstart);
3306 switch (settings.stablerandom)
3310 VectorRandom(clipend);
3311 if (settings.bounceanglediffuse)
3313 // we want random to be stable, so we still have to do all the random we would have done
3314 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3315 VectorRandom(bouncerandom[bouncecount]);
3320 VectorLehmerRandom(&randomseed, clipend);
3321 if (settings.bounceanglediffuse)
3323 // we want random to be stable, so we still have to do all the random we would have done
3324 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3325 VectorLehmerRandom(&randomseed, bouncerandom[bouncecount]);
3330 VectorCheeseRandom(seed, clipend);
3331 if (settings.bounceanglediffuse)
3333 // we want random to be stable, so we still have to do all the random we would have done
3334 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3335 VectorCheeseRandom(seed, bouncerandom[bouncecount]);
3339 VectorMA(clipstart, radius, clipend, clipend);
3340 for (bouncecount = 0;;bouncecount++)
3342 r_refdef.stats[r_stat_bouncegrid_traces]++;
3343 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
3344 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
3345 if (settings.staticmode || settings.stablerandom <= 0)
3347 // static mode fires a LOT of rays but none of them are identical, so they are not cached
3348 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
3349 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);
3353 // dynamic mode fires many rays and most will match the cache from the previous frame
3354 cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask, skipsupercontentsmask);
3356 if (bouncecount > 0 || settings.includedirectlighting)
3359 VectorCopy(cliptrace.endpos, hitpos);
3360 R_Shadow_BounceGrid_AddSplatPath(clipstart, hitpos, shotcolor);
3362 if (cliptrace.fraction >= 1.0f)
3364 r_refdef.stats[r_stat_bouncegrid_hits]++;
3365 if (bouncecount >= maxbounce)
3367 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
3368 // also clamp the resulting color to never add energy, even if the user requests extreme values
3369 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
3370 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
3372 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
3373 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
3374 surfcolor[0] = min(surfcolor[0], 1.0f);
3375 surfcolor[1] = min(surfcolor[1], 1.0f);
3376 surfcolor[2] = min(surfcolor[2], 1.0f);
3377 VectorMultiply(shotcolor, surfcolor, shotcolor);
3378 if (VectorLength2(baseshotcolor) == 0.0f)
3380 r_refdef.stats[r_stat_bouncegrid_bounces]++;
3381 if (settings.bounceanglediffuse)
3383 // random direction, primarily along plane normal
3384 s = VectorDistance(cliptrace.endpos, clipend);
3385 VectorMA(cliptrace.plane.normal, 0.95f, bouncerandom[bouncecount], clipend);
3386 VectorNormalize(clipend);
3387 VectorScale(clipend, s, clipend);
3391 // reflect the remaining portion of the line across plane normal
3392 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
3393 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
3395 // calculate the new line start and end
3396 VectorCopy(cliptrace.endpos, clipstart);
3397 VectorAdd(clipstart, clipend, clipend);
3403 void R_Shadow_UpdateBounceGridTexture(void)
3405 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3406 r_shadow_bouncegrid_settings_t settings;
3407 qboolean enable = false;
3408 qboolean settingschanged;
3409 unsigned int range; // number of world lights
3410 unsigned int range1; // number of dynamic lights (or zero if disabled)
3411 unsigned int range2; // range+range1
3412 float photonscaling;
3414 enable = R_Shadow_BounceGrid_CheckEnable(flag);
3416 R_Shadow_BounceGrid_GenerateSettings(&settings);
3418 // changing intensity does not require an update
3419 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
3421 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
3423 // when settings change, we free everything as it is just simpler that way.
3424 if (settingschanged || !enable)
3426 // not enabled, make sure we free anything we don't need anymore.
3427 if (r_shadow_bouncegrid_state.texture)
3429 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3430 r_shadow_bouncegrid_state.texture = NULL;
3432 r_shadow_bouncegrid_state.highpixels = NULL;
3433 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
3434 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
3435 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
3436 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
3437 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
3438 r_shadow_bouncegrid_state.maxsplatpaths = 0;
3439 r_shadow_bouncegrid_state.numpixels = 0;
3440 r_shadow_bouncegrid_state.directional = false;
3446 // if all the settings seem identical to the previous update, return
3447 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
3450 // store the new settings
3451 r_shadow_bouncegrid_state.settings = settings;
3453 R_Shadow_BounceGrid_UpdateSpacing();
3455 // get the range of light numbers we'll be looping over:
3456 // range = static lights
3457 // range1 = dynamic lights (optional)
3458 // range2 = range + range1
3459 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3460 range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
3461 range2 = range + range1;
3463 // calculate weighting factors for distributing photons among the lights
3464 R_Shadow_BounceGrid_AssignPhotons(&settings, range, range1, range2, flag, &photonscaling);
3466 // trace the photons from lights and accumulate illumination
3467 R_Shadow_BounceGrid_TracePhotons(settings, range, range1, range2, photonscaling, flag);
3469 // clear the texture
3470 R_Shadow_BounceGrid_ClearPixels();
3472 // accumulate the light splatting into texture
3473 R_Shadow_BounceGrid_PerformSplats();
3475 // apply a mild blur filter to the texture
3476 R_Shadow_BounceGrid_BlurPixels();
3478 // convert the pixels to lower precision and upload the texture
3479 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
3481 // after we compute the static lighting we don't need to keep the highpixels array around
3482 if (settings.staticmode)
3484 r_shadow_bouncegrid_state.highpixels = NULL;
3485 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
3486 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
3487 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
3488 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
3489 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
3490 r_shadow_bouncegrid_state.maxsplatpaths = 0;
3494 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
3496 R_Shadow_RenderMode_Reset();
3497 GL_BlendFunc(GL_ONE, GL_ONE);
3498 GL_DepthRange(0, 1);
3499 GL_DepthTest(r_showshadowvolumes.integer < 2);
3500 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
3501 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
3502 GL_CullFace(GL_NONE);
3503 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
3506 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
3508 R_Shadow_RenderMode_Reset();
3509 GL_BlendFunc(GL_ONE, GL_ONE);
3510 GL_DepthRange(0, 1);
3511 GL_DepthTest(r_showlighting.integer < 2);
3512 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
3514 GL_DepthFunc(GL_EQUAL);
3515 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
3516 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
3519 void R_Shadow_RenderMode_End(void)
3521 R_Shadow_RenderMode_Reset();
3522 R_Shadow_RenderMode_ActiveLight(NULL);
3524 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3525 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3528 int bboxedges[12][2] =
3547 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
3549 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
3551 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
3552 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
3553 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
3554 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
3557 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
3558 return true; // invisible
3559 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
3560 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
3561 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
3562 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
3563 r_refdef.stats[r_stat_lights_scissored]++;
3567 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
3570 const float *vertex3f;
3571 const float *normal3f;
3573 float dist, dot, distintensity, shadeintensity, v[3], n[3];
3574 switch (r_shadow_rendermode)
3576 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3577 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3578 if (VectorLength2(diffusecolor) > 0)
3580 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)
3582 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3583 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3584 if ((dot = DotProduct(n, v)) < 0)
3586 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3587 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
3590 VectorCopy(ambientcolor, color4f);
3591 if (r_refdef.fogenabled)
3594 f = RSurf_FogVertex(vertex3f);
3595 VectorScale(color4f, f, color4f);
3602 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3604 VectorCopy(ambientcolor, color4f);
3605 if (r_refdef.fogenabled)
3608 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3609 f = RSurf_FogVertex(vertex3f);
3610 VectorScale(color4f + 4*i, f, color4f);
3616 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3617 if (VectorLength2(diffusecolor) > 0)
3619 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)
3621 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3622 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3624 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3625 if ((dot = DotProduct(n, v)) < 0)
3627 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3628 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3629 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3630 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3634 color4f[0] = ambientcolor[0] * distintensity;
3635 color4f[1] = ambientcolor[1] * distintensity;
3636 color4f[2] = ambientcolor[2] * distintensity;
3638 if (r_refdef.fogenabled)
3641 f = RSurf_FogVertex(vertex3f);
3642 VectorScale(color4f, f, color4f);
3646 VectorClear(color4f);
3652 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3654 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3655 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3657 color4f[0] = ambientcolor[0] * distintensity;
3658 color4f[1] = ambientcolor[1] * distintensity;
3659 color4f[2] = ambientcolor[2] * distintensity;
3660 if (r_refdef.fogenabled)
3663 f = RSurf_FogVertex(vertex3f);
3664 VectorScale(color4f, f, color4f);
3668 VectorClear(color4f);
3673 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3674 if (VectorLength2(diffusecolor) > 0)
3676 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)
3678 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3679 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3681 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3682 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3683 if ((dot = DotProduct(n, v)) < 0)
3685 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3686 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3687 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3688 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3692 color4f[0] = ambientcolor[0] * distintensity;
3693 color4f[1] = ambientcolor[1] * distintensity;
3694 color4f[2] = ambientcolor[2] * distintensity;
3696 if (r_refdef.fogenabled)
3699 f = RSurf_FogVertex(vertex3f);
3700 VectorScale(color4f, f, color4f);
3704 VectorClear(color4f);
3710 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3712 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3713 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3715 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3716 color4f[0] = ambientcolor[0] * distintensity;
3717 color4f[1] = ambientcolor[1] * distintensity;
3718 color4f[2] = ambientcolor[2] * distintensity;
3719 if (r_refdef.fogenabled)
3722 f = RSurf_FogVertex(vertex3f);
3723 VectorScale(color4f, f, color4f);
3727 VectorClear(color4f);
3737 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3739 // used to display how many times a surface is lit for level design purposes
3740 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3741 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3745 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
3747 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3748 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
3752 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3759 int newnumtriangles;
3763 int maxtriangles = 1024;
3764 int newelements[1024*3];
3765 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3766 for (renders = 0;renders < 4;renders++)
3771 newnumtriangles = 0;
3773 // due to low fillrate on the cards this vertex lighting path is
3774 // designed for, we manually cull all triangles that do not
3775 // contain a lit vertex
3776 // this builds batches of triangles from multiple surfaces and
3777 // renders them at once
3778 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3780 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3782 if (newnumtriangles)
3784 newfirstvertex = min(newfirstvertex, e[0]);
3785 newlastvertex = max(newlastvertex, e[0]);
3789 newfirstvertex = e[0];
3790 newlastvertex = e[0];
3792 newfirstvertex = min(newfirstvertex, e[1]);
3793 newlastvertex = max(newlastvertex, e[1]);
3794 newfirstvertex = min(newfirstvertex, e[2]);
3795 newlastvertex = max(newlastvertex, e[2]);
3801 if (newnumtriangles >= maxtriangles)
3803 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3804 newnumtriangles = 0;
3810 if (newnumtriangles >= 1)
3812 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3815 // if we couldn't find any lit triangles, exit early
3818 // now reduce the intensity for the next overbright pass
3819 // we have to clamp to 0 here incase the drivers have improper
3820 // handling of negative colors
3821 // (some old drivers even have improper handling of >1 color)
3823 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3825 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3827 c[0] = max(0, c[0] - 1);
3828 c[1] = max(0, c[1] - 1);
3829 c[2] = max(0, c[2] - 1);
3841 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
3843 // OpenGL 1.1 path (anything)
3844 float ambientcolorbase[3], diffusecolorbase[3];
3845 float ambientcolorpants[3], diffusecolorpants[3];
3846 float ambientcolorshirt[3], diffusecolorshirt[3];
3847 const float *surfacecolor = rsurface.texture->dlightcolor;
3848 const float *surfacepants = rsurface.colormap_pantscolor;
3849 const float *surfaceshirt = rsurface.colormap_shirtcolor;
3850 rtexture_t *basetexture = rsurface.texture->basetexture;
3851 rtexture_t *pantstexture = rsurface.texture->pantstexture;
3852 rtexture_t *shirttexture = rsurface.texture->shirttexture;
3853 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3854 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3855 ambientscale *= 2 * r_refdef.view.colorscale;
3856 diffusescale *= 2 * r_refdef.view.colorscale;
3857 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3858 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3859 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3860 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3861 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3862 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
3863 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3864 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
3865 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3866 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
3867 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
3868 R_Mesh_TexBind(0, basetexture);
3869 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
3870 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
3871 switch(r_shadow_rendermode)
3873 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3874 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
3875 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3876 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3877 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3879 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3880 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
3881 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
3882 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
3883 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3885 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3886 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
3887 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3888 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3889 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3891 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3896 //R_Mesh_TexBind(0, basetexture);
3897 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
3900 R_Mesh_TexBind(0, pantstexture);
3901 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
3905 R_Mesh_TexBind(0, shirttexture);
3906 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
3910 extern cvar_t gl_lightmaps;
3911 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3913 float ambientscale, diffusescale, specularscale;
3915 float lightcolor[3];
3916 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
3917 ambientscale = rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient;
3918 diffusescale = rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient);
3919 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3920 if (!r_shadow_usenormalmap.integer)
3922 ambientscale += 1.0f * diffusescale;
3926 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
3928 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
3931 VectorNegate(lightcolor, lightcolor);
3932 GL_BlendEquationSubtract(true);
3934 RSurf_SetupDepthAndCulling();
3935 switch (r_shadow_rendermode)
3937 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3938 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3939 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
3941 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3942 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
3944 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3945 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3946 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3947 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3948 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
3951 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3955 GL_BlendEquationSubtract(false);
3958 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)
3960 matrix4x4_t tempmatrix = *matrix;
3961 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3963 // if this light has been compiled before, free the associated data
3964 R_RTLight_Uncompile(rtlight);
3966 // clear it completely to avoid any lingering data
3967 memset(rtlight, 0, sizeof(*rtlight));
3969 // copy the properties
3970 rtlight->matrix_lighttoworld = tempmatrix;
3971 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3972 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3973 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3974 VectorCopy(color, rtlight->color);
3975 rtlight->cubemapname[0] = 0;
3976 if (cubemapname && cubemapname[0])
3977 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3978 rtlight->shadow = shadow;
3979 rtlight->corona = corona;
3980 rtlight->style = style;
3981 rtlight->isstatic = isstatic;
3982 rtlight->coronasizescale = coronasizescale;
3983 rtlight->ambientscale = ambientscale;
3984 rtlight->diffusescale = diffusescale;
3985 rtlight->specularscale = specularscale;
3986 rtlight->flags = flags;
3988 // compute derived data
3989 //rtlight->cullradius = rtlight->radius;
3990 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3991 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3992 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3993 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3994 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3995 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3996 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3999 // compiles rtlight geometry
4000 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
4001 void R_RTLight_Compile(rtlight_t *rtlight)
4004 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
4005 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
4006 entity_render_t *ent = r_refdef.scene.worldentity;
4007 dp_model_t *model = r_refdef.scene.worldmodel;
4008 unsigned char *data;
4011 // compile the light
4012 rtlight->compiled = true;
4013 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
4014 rtlight->static_numleafs = 0;
4015 rtlight->static_numleafpvsbytes = 0;
4016 rtlight->static_leaflist = NULL;
4017 rtlight->static_leafpvs = NULL;
4018 rtlight->static_numsurfaces = 0;
4019 rtlight->static_surfacelist = NULL;
4020 rtlight->static_shadowmap_receivers = 0x3F;
4021 rtlight->static_shadowmap_casters = 0x3F;
4022 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
4023 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
4024 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
4025 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
4026 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
4027 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
4029 if (model && model->GetLightInfo)
4031 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
4032 r_shadow_compilingrtlight = rtlight;
4033 R_FrameData_SetMark();
4034 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);
4035 R_FrameData_ReturnToMark();
4036 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
4037 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
4038 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
4039 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
4040 rtlight->static_numsurfaces = numsurfaces;
4041 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
4042 rtlight->static_numleafs = numleafs;
4043 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
4044 rtlight->static_numleafpvsbytes = numleafpvsbytes;
4045 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
4046 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
4047 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
4048 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
4049 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
4050 if (rtlight->static_numsurfaces)
4051 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
4052 if (rtlight->static_numleafs)
4053 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
4054 if (rtlight->static_numleafpvsbytes)
4055 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
4056 if (rtlight->static_numshadowtrispvsbytes)
4057 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
4058 if (rtlight->static_numlighttrispvsbytes)
4059 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
4060 R_FrameData_SetMark();
4061 switch (rtlight->shadowmode)
4063 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4064 if (model->CompileShadowMap && rtlight->shadow)
4065 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
4068 if (model->CompileShadowVolume && rtlight->shadow)
4069 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
4072 R_FrameData_ReturnToMark();
4073 // now we're done compiling the rtlight
4074 r_shadow_compilingrtlight = NULL;
4078 // use smallest available cullradius - box radius or light radius
4079 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
4080 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
4082 shadowzpasstris = 0;
4083 if (rtlight->static_meshchain_shadow_zpass)
4084 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
4085 shadowzpasstris += mesh->numtriangles;
4087 shadowzfailtris = 0;
4088 if (rtlight->static_meshchain_shadow_zfail)
4089 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
4090 shadowzfailtris += mesh->numtriangles;
4093 if (rtlight->static_numlighttrispvsbytes)
4094 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
4095 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
4099 if (rtlight->static_numshadowtrispvsbytes)
4100 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
4101 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
4104 if (developer_extra.integer)
4105 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);
4108 void R_RTLight_Uncompile(rtlight_t *rtlight)
4110 if (rtlight->compiled)
4112 if (rtlight->static_meshchain_shadow_zpass)
4113 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
4114 rtlight->static_meshchain_shadow_zpass = NULL;
4115 if (rtlight->static_meshchain_shadow_zfail)
4116 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
4117 rtlight->static_meshchain_shadow_zfail = NULL;
4118 if (rtlight->static_meshchain_shadow_shadowmap)
4119 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
4120 rtlight->static_meshchain_shadow_shadowmap = NULL;
4121 // these allocations are grouped
4122 if (rtlight->static_surfacelist)
4123 Mem_Free(rtlight->static_surfacelist);
4124 rtlight->static_numleafs = 0;
4125 rtlight->static_numleafpvsbytes = 0;
4126 rtlight->static_leaflist = NULL;
4127 rtlight->static_leafpvs = NULL;
4128 rtlight->static_numsurfaces = 0;
4129 rtlight->static_surfacelist = NULL;
4130 rtlight->static_numshadowtrispvsbytes = 0;
4131 rtlight->static_shadowtrispvs = NULL;
4132 rtlight->static_numlighttrispvsbytes = 0;
4133 rtlight->static_lighttrispvs = NULL;
4134 rtlight->compiled = false;
4138 void R_Shadow_UncompileWorldLights(void)
4142 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4143 for (lightindex = 0;lightindex < range;lightindex++)
4145 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4148 R_RTLight_Uncompile(&light->rtlight);
4152 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
4156 // reset the count of frustum planes
4157 // see rtlight->cached_frustumplanes definition for how much this array
4159 rtlight->cached_numfrustumplanes = 0;
4161 if (r_trippy.integer)
4164 // haven't implemented a culling path for ortho rendering
4165 if (!r_refdef.view.useperspective)
4167 // check if the light is on screen and copy the 4 planes if it is
4168 for (i = 0;i < 4;i++)
4169 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4172 for (i = 0;i < 4;i++)
4173 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4178 // generate a deformed frustum that includes the light origin, this is
4179 // used to cull shadow casting surfaces that can not possibly cast a
4180 // shadow onto the visible light-receiving surfaces, which can be a
4183 // if the light origin is onscreen the result will be 4 planes exactly
4184 // if the light origin is offscreen on only one axis the result will
4185 // be exactly 5 planes (split-side case)
4186 // if the light origin is offscreen on two axes the result will be
4187 // exactly 4 planes (stretched corner case)
4188 for (i = 0;i < 4;i++)
4190 // quickly reject standard frustum planes that put the light
4191 // origin outside the frustum
4192 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4195 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4197 // if all the standard frustum planes were accepted, the light is onscreen
4198 // otherwise we need to generate some more planes below...
4199 if (rtlight->cached_numfrustumplanes < 4)
4201 // at least one of the stock frustum planes failed, so we need to
4202 // create one or two custom planes to enclose the light origin
4203 for (i = 0;i < 4;i++)
4205 // create a plane using the view origin and light origin, and a
4206 // single point from the frustum corner set
4207 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
4208 VectorNormalize(plane.normal);
4209 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
4210 // see if this plane is backwards and flip it if so
4211 for (j = 0;j < 4;j++)
4212 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4216 VectorNegate(plane.normal, plane.normal);
4218 // flipped plane, test again to see if it is now valid
4219 for (j = 0;j < 4;j++)
4220 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4222 // if the plane is still not valid, then it is dividing the
4223 // frustum and has to be rejected
4227 // we have created a valid plane, compute extra info
4228 PlaneClassify(&plane);
4230 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4232 // if we've found 5 frustum planes then we have constructed a
4233 // proper split-side case and do not need to keep searching for
4234 // planes to enclose the light origin
4235 if (rtlight->cached_numfrustumplanes == 5)
4243 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
4245 plane = rtlight->cached_frustumplanes[i];
4246 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));
4251 // now add the light-space box planes if the light box is rotated, as any
4252 // caster outside the oriented light box is irrelevant (even if it passed
4253 // the worldspace light box, which is axial)
4254 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
4256 for (i = 0;i < 6;i++)
4260 v[i >> 1] = (i & 1) ? -1 : 1;
4261 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
4262 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
4263 plane.dist = VectorNormalizeLength(plane.normal);
4264 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
4265 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4271 // add the world-space reduced box planes
4272 for (i = 0;i < 6;i++)
4274 VectorClear(plane.normal);
4275 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
4276 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
4277 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4286 // reduce all plane distances to tightly fit the rtlight cull box, which
4288 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4289 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4290 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4291 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4292 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4293 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4294 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4295 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4296 oldnum = rtlight->cached_numfrustumplanes;
4297 rtlight->cached_numfrustumplanes = 0;
4298 for (j = 0;j < oldnum;j++)
4300 // find the nearest point on the box to this plane
4301 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
4302 for (i = 1;i < 8;i++)
4304 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
4305 if (bestdist > dist)
4308 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);
4309 // if the nearest point is near or behind the plane, we want this
4310 // plane, otherwise the plane is useless as it won't cull anything
4311 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
4313 PlaneClassify(&rtlight->cached_frustumplanes[j]);
4314 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
4321 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
4325 RSurf_ActiveWorldEntity();
4327 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4330 GL_CullFace(GL_NONE);
4331 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
4332 for (;mesh;mesh = mesh->next)
4334 if (!mesh->sidetotals[r_shadow_shadowmapside])
4336 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
4337 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4338 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);
4342 else if (r_refdef.scene.worldentity->model)
4343 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);
4345 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4348 static void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
4350 qboolean zpass = false;
4353 int surfacelistindex;
4354 msurface_t *surface;
4356 // if triangle neighbors are disabled, shadowvolumes are disabled
4357 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
4360 RSurf_ActiveWorldEntity();
4362 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4365 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
4367 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
4368 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
4370 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
4371 for (;mesh;mesh = mesh->next)
4373 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->numtriangles;
4374 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4375 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
4377 // increment stencil if frontface is infront of depthbuffer
4378 GL_CullFace(r_refdef.view.cullface_back);
4379 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
4380 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);
4381 // decrement stencil if backface is infront of depthbuffer
4382 GL_CullFace(r_refdef.view.cullface_front);
4383 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
4385 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
4387 // decrement stencil if backface is behind depthbuffer
4388 GL_CullFace(r_refdef.view.cullface_front);
4389 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
4390 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);
4391 // increment stencil if frontface is behind depthbuffer
4392 GL_CullFace(r_refdef.view.cullface_back);
4393 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
4395 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);
4399 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
4401 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
4402 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
4403 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
4405 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
4406 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
4407 if (CHECKPVSBIT(trispvs, t))
4408 shadowmarklist[numshadowmark++] = t;
4410 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);
4412 else if (numsurfaces)
4414 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);
4417 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4420 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
4422 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
4423 vec_t relativeshadowradius;
4424 RSurf_ActiveModelEntity(ent, false, false, false);
4425 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
4426 // we need to re-init the shader for each entity because the matrix changed
4427 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
4428 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
4429 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
4430 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
4431 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
4432 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
4433 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
4434 switch (r_shadow_rendermode)
4436 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
4437 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4440 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4443 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4446 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
4448 // set up properties for rendering light onto this entity
4449 RSurf_ActiveModelEntity(ent, true, true, false);
4450 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
4451 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4452 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4453 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4456 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
4458 if (!r_refdef.scene.worldmodel->DrawLight)
4461 // set up properties for rendering light onto this entity
4462 RSurf_ActiveWorldEntity();
4463 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
4464 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4465 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4466 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4468 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
4470 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4473 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
4475 dp_model_t *model = ent->model;
4476 if (!model->DrawLight)
4479 R_Shadow_SetupEntityLight(ent);
4481 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
4483 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4486 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
4490 int numleafs, numsurfaces;
4491 int *leaflist, *surfacelist;
4492 unsigned char *leafpvs;
4493 unsigned char *shadowtrispvs;
4494 unsigned char *lighttrispvs;
4495 //unsigned char *surfacesides;
4496 int numlightentities;
4497 int numlightentities_noselfshadow;
4498 int numshadowentities;
4499 int numshadowentities_noselfshadow;
4500 // FIXME: bounds check lightentities and shadowentities, etc.
4501 static entity_render_t *lightentities[MAX_EDICTS];
4502 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
4503 static entity_render_t *shadowentities[MAX_EDICTS];
4504 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
4506 qboolean castshadows;
4508 rtlight->draw = false;
4509 rtlight->cached_numlightentities = 0;
4510 rtlight->cached_numlightentities_noselfshadow = 0;
4511 rtlight->cached_numshadowentities = 0;
4512 rtlight->cached_numshadowentities_noselfshadow = 0;
4513 rtlight->cached_numsurfaces = 0;
4514 rtlight->cached_lightentities = NULL;
4515 rtlight->cached_lightentities_noselfshadow = NULL;
4516 rtlight->cached_shadowentities = NULL;
4517 rtlight->cached_shadowentities_noselfshadow = NULL;
4518 rtlight->cached_shadowtrispvs = NULL;
4519 rtlight->cached_lighttrispvs = NULL;
4520 rtlight->cached_surfacelist = NULL;
4521 rtlight->shadowmapsidesize = 0;
4523 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
4524 // skip lights that are basically invisible (color 0 0 0)
4525 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
4527 // loading is done before visibility checks because loading should happen
4528 // all at once at the start of a level, not when it stalls gameplay.
4529 // (especially important to benchmarks)
4531 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
4533 if (rtlight->compiled)
4534 R_RTLight_Uncompile(rtlight);
4535 R_RTLight_Compile(rtlight);
4539 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
4541 // look up the light style value at this time
4542 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4543 VectorScale(rtlight->color, f, rtlight->currentcolor);
4545 if (rtlight->selected)
4547 f = 2 + sin(realtime * M_PI * 4.0);
4548 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
4552 // if lightstyle is currently off, don't draw the light
4553 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
4556 // skip processing on corona-only lights
4560 // if the light box is offscreen, skip it
4561 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
4564 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
4565 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
4567 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4569 // 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
4570 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
4573 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
4575 // compiled light, world available and can receive realtime lighting
4576 // retrieve leaf information
4577 numleafs = rtlight->static_numleafs;
4578 leaflist = rtlight->static_leaflist;
4579 leafpvs = rtlight->static_leafpvs;
4580 numsurfaces = rtlight->static_numsurfaces;
4581 surfacelist = rtlight->static_surfacelist;
4582 //surfacesides = NULL;
4583 shadowtrispvs = rtlight->static_shadowtrispvs;
4584 lighttrispvs = rtlight->static_lighttrispvs;
4586 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4588 // dynamic light, world available and can receive realtime lighting
4589 // calculate lit surfaces and leafs
4590 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);
4591 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4592 leaflist = r_shadow_buffer_leaflist;
4593 leafpvs = r_shadow_buffer_leafpvs;
4594 surfacelist = r_shadow_buffer_surfacelist;
4595 //surfacesides = r_shadow_buffer_surfacesides;
4596 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4597 lighttrispvs = r_shadow_buffer_lighttrispvs;
4598 // if the reduced leaf bounds are offscreen, skip it
4599 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4610 //surfacesides = NULL;
4611 shadowtrispvs = NULL;
4612 lighttrispvs = NULL;
4614 // check if light is illuminating any visible leafs
4617 for (i = 0; i < numleafs; i++)
4618 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4624 // make a list of lit entities and shadow casting entities
4625 numlightentities = 0;
4626 numlightentities_noselfshadow = 0;
4627 numshadowentities = 0;
4628 numshadowentities_noselfshadow = 0;
4630 // add dynamic entities that are lit by the light
4631 for (i = 0; i < r_refdef.scene.numentities; i++)
4634 entity_render_t *ent = r_refdef.scene.entities[i];
4636 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4638 // skip the object entirely if it is not within the valid
4639 // shadow-casting region (which includes the lit region)
4640 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
4642 if (!(model = ent->model))
4644 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4646 // this entity wants to receive light, is visible, and is
4647 // inside the light box
4648 // TODO: check if the surfaces in the model can receive light
4649 // so now check if it's in a leaf seen by the light
4650 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))
4652 if (ent->flags & RENDER_NOSELFSHADOW)
4653 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
4655 lightentities[numlightentities++] = ent;
4656 // since it is lit, it probably also casts a shadow...
4657 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4658 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4659 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4661 // note: exterior models without the RENDER_NOSELFSHADOW
4662 // flag still create a RENDER_NOSELFSHADOW shadow but
4663 // are lit normally, this means that they are
4664 // self-shadowing but do not shadow other
4665 // RENDER_NOSELFSHADOW entities such as the gun
4666 // (very weird, but keeps the player shadow off the gun)
4667 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4668 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4670 shadowentities[numshadowentities++] = ent;
4673 else if (ent->flags & RENDER_SHADOW)
4675 // this entity is not receiving light, but may still need to
4677 // TODO: check if the surfaces in the model can cast shadow
4678 // now check if it is in a leaf seen by the light
4679 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))
4681 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4682 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4683 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4685 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4686 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4688 shadowentities[numshadowentities++] = ent;
4693 // return if there's nothing at all to light
4694 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4697 // count this light in the r_speeds
4698 r_refdef.stats[r_stat_lights]++;
4700 // flag it as worth drawing later
4701 rtlight->draw = true;
4703 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
4704 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4706 numshadowentities = numshadowentities_noselfshadow = 0;
4707 rtlight->castshadows = castshadows;
4709 // cache all the animated entities that cast a shadow but are not visible
4710 for (i = 0; i < numshadowentities; i++)
4711 R_AnimCache_GetEntity(shadowentities[i], false, false);
4712 for (i = 0; i < numshadowentities_noselfshadow; i++)
4713 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4715 // 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)
4716 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
4718 for (i = 0; i < numshadowentities_noselfshadow; i++)
4719 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
4720 numshadowentities_noselfshadow = 0;
4723 // we can convert noselfshadow to regular if there are no casters of that type
4724 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
4726 for (i = 0; i < numlightentities_noselfshadow; i++)
4727 lightentities[numlightentities++] = lightentities_noselfshadow[i];
4728 numlightentities_noselfshadow = 0;
4731 // allocate some temporary memory for rendering this light later in the frame
4732 // reusable buffers need to be copied, static data can be used as-is
4733 rtlight->cached_numlightentities = numlightentities;
4734 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
4735 rtlight->cached_numshadowentities = numshadowentities;
4736 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4737 rtlight->cached_numsurfaces = numsurfaces;
4738 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4739 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4740 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4741 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4742 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4744 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4745 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4746 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4747 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4748 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4752 // compiled light data
4753 rtlight->cached_shadowtrispvs = shadowtrispvs;
4754 rtlight->cached_lighttrispvs = lighttrispvs;
4755 rtlight->cached_surfacelist = surfacelist;
4758 if (R_Shadow_ShadowMappingEnabled())
4760 // figure out the shadowmapping parameters for this light
4761 vec3_t nearestpoint;
4764 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4765 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4766 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4767 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4768 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
4769 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4770 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4771 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4772 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
4776 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
4780 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4781 int numlightentities;
4782 int numlightentities_noselfshadow;
4783 int numshadowentities;
4784 int numshadowentities_noselfshadow;
4785 entity_render_t **lightentities;
4786 entity_render_t **lightentities_noselfshadow;
4787 entity_render_t **shadowentities;
4788 entity_render_t **shadowentities_noselfshadow;
4790 static unsigned char entitysides[MAX_EDICTS];
4791 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4797 matrix4x4_t radiustolight;
4799 // check if we cached this light this frame (meaning it is worth drawing)
4800 if (!rtlight->draw || !rtlight->castshadows)
4803 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
4804 if (rtlight->shadowmapatlassidesize == 0)
4806 rtlight->castshadows = false;
4810 // set up a scissor rectangle for this light
4811 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4814 // don't let sound skip if going slow
4815 if (r_refdef.scene.extraupdate)
4818 numlightentities = rtlight->cached_numlightentities;
4819 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4820 numshadowentities = rtlight->cached_numshadowentities;
4821 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4822 numsurfaces = rtlight->cached_numsurfaces;
4823 lightentities = rtlight->cached_lightentities;
4824 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4825 shadowentities = rtlight->cached_shadowentities;
4826 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4827 shadowtrispvs = rtlight->cached_shadowtrispvs;
4828 lighttrispvs = rtlight->cached_lighttrispvs;
4829 surfacelist = rtlight->cached_surfacelist;
4831 // make this the active rtlight for rendering purposes
4832 R_Shadow_RenderMode_ActiveLight(rtlight);
4834 radiustolight = rtlight->matrix_worldtolight;
4835 Matrix4x4_Abs(&radiustolight);
4837 size = rtlight->shadowmapatlassidesize;
4838 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4840 surfacesides = NULL;
4845 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4847 castermask = rtlight->static_shadowmap_casters;
4848 receivermask = rtlight->static_shadowmap_receivers;
4852 surfacesides = r_shadow_buffer_surfacesides;
4853 for (i = 0; i < numsurfaces; i++)
4855 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4856 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4857 castermask |= surfacesides[i];
4858 receivermask |= surfacesides[i];
4863 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
4864 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4865 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
4866 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4868 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4872 for (i = 0; i < numshadowentities; i++)
4873 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4874 for (i = 0; i < numshadowentities_noselfshadow; i++)
4875 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4878 // there is no need to render shadows for sides that have no receivers...
4879 castermask &= receivermask;
4881 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
4883 // render shadow casters into shadowmaps for this light
4884 for (side = 0; side < 6; side++)
4886 int bit = 1 << side;
4887 if (castermask & bit)
4889 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
4891 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4892 for (i = 0; i < numshadowentities; i++)
4893 if (entitysides[i] & bit)
4894 R_Shadow_DrawEntityShadow(shadowentities[i]);
4895 for (i = 0; i < numshadowentities_noselfshadow; i++)
4896 if (entitysides_noselfshadow[i] & bit)
4897 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4900 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
4901 if (numshadowentities_noselfshadow)
4903 for (side = 0; side < 6; side++)
4905 int bit = 1 << side;
4906 if (castermask & bit)
4908 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
4910 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4911 for (i = 0; i < numshadowentities; i++)
4912 if (entitysides[i] & bit)
4913 R_Shadow_DrawEntityShadow(shadowentities[i]);
4919 static void R_Shadow_DrawLight(rtlight_t *rtlight)
4923 unsigned char *shadowtrispvs, *lighttrispvs;
4924 int numlightentities;
4925 int numlightentities_noselfshadow;
4926 int numshadowentities;
4927 int numshadowentities_noselfshadow;
4928 entity_render_t **lightentities;
4929 entity_render_t **lightentities_noselfshadow;
4930 entity_render_t **shadowentities;
4931 entity_render_t **shadowentities_noselfshadow;
4933 qboolean castshadows;
4935 // check if we cached this light this frame (meaning it is worth drawing)
4939 // set up a scissor rectangle for this light
4940 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4943 // don't let sound skip if going slow
4944 if (r_refdef.scene.extraupdate)
4947 numlightentities = rtlight->cached_numlightentities;
4948 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4949 numshadowentities = rtlight->cached_numshadowentities;
4950 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4951 numsurfaces = rtlight->cached_numsurfaces;
4952 lightentities = rtlight->cached_lightentities;
4953 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4954 shadowentities = rtlight->cached_shadowentities;
4955 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4956 shadowtrispvs = rtlight->cached_shadowtrispvs;
4957 lighttrispvs = rtlight->cached_lighttrispvs;
4958 surfacelist = rtlight->cached_surfacelist;
4959 castshadows = rtlight->castshadows;
4961 // make this the active rtlight for rendering purposes
4962 R_Shadow_RenderMode_ActiveLight(rtlight);
4964 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4966 // optionally draw visible shape of the shadow volumes
4967 // for performance analysis by level designers
4968 R_Shadow_RenderMode_VisibleShadowVolumes();
4970 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4971 for (i = 0;i < numshadowentities;i++)
4972 R_Shadow_DrawEntityShadow(shadowentities[i]);
4973 for (i = 0;i < numshadowentities_noselfshadow;i++)
4974 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4975 R_Shadow_RenderMode_VisibleLighting(false, false);
4978 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4980 // optionally draw the illuminated areas
4981 // for performance analysis by level designers
4982 R_Shadow_RenderMode_VisibleLighting(false, false);
4984 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4985 for (i = 0;i < numlightentities;i++)
4986 R_Shadow_DrawEntityLight(lightentities[i]);
4987 for (i = 0;i < numlightentities_noselfshadow;i++)
4988 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4991 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4995 float shadowmapoffsetnoselfshadow = 0;
4996 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4997 Matrix4x4_Abs(&radiustolight);
4999 size = rtlight->shadowmapatlassidesize;
5000 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
5002 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
5004 if (rtlight->cached_numshadowentities_noselfshadow)
5005 shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
5007 // render lighting using the depth texture as shadowmap
5008 // draw lighting in the unmasked areas
5009 if (numsurfaces + numlightentities)
5011 R_Shadow_RenderMode_Lighting(false, false, true, false);
5012 // draw lighting in the unmasked areas
5014 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5015 for (i = 0; i < numlightentities; i++)
5016 R_Shadow_DrawEntityLight(lightentities[i]);
5018 // offset to the noselfshadow part of the atlas and draw those too
5019 if (numlightentities_noselfshadow)
5021 R_Shadow_RenderMode_Lighting(false, false, true, true);
5022 for (i = 0; i < numlightentities_noselfshadow; i++)
5023 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5026 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5027 if (r_shadow_usingdeferredprepass)
5028 R_Shadow_RenderMode_DrawDeferredLight(true);
5030 else if (castshadows && vid.stencil)
5032 // draw stencil shadow volumes to mask off pixels that are in shadow
5033 // so that they won't receive lighting
5034 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
5035 R_Shadow_ClearStencil();
5038 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
5039 for (i = 0;i < numshadowentities;i++)
5040 R_Shadow_DrawEntityShadow(shadowentities[i]);
5042 // draw lighting in the unmasked areas
5043 R_Shadow_RenderMode_Lighting(true, false, false, false);
5044 for (i = 0;i < numlightentities_noselfshadow;i++)
5045 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5047 for (i = 0;i < numshadowentities_noselfshadow;i++)
5048 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5050 // draw lighting in the unmasked areas
5051 R_Shadow_RenderMode_Lighting(true, false, false, false);
5053 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5054 for (i = 0;i < numlightentities;i++)
5055 R_Shadow_DrawEntityLight(lightentities[i]);
5057 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5058 if (r_shadow_usingdeferredprepass)
5059 R_Shadow_RenderMode_DrawDeferredLight(false);
5063 // draw lighting in the unmasked areas
5064 R_Shadow_RenderMode_Lighting(false, false, false, false);
5066 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5067 for (i = 0;i < numlightentities;i++)
5068 R_Shadow_DrawEntityLight(lightentities[i]);
5069 for (i = 0;i < numlightentities_noselfshadow;i++)
5070 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5072 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5073 if (r_shadow_usingdeferredprepass)
5074 R_Shadow_RenderMode_DrawDeferredLight(false);
5078 static void R_Shadow_FreeDeferred(void)
5080 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
5081 r_shadow_prepassgeometryfbo = 0;
5083 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
5084 r_shadow_prepasslightingdiffusespecularfbo = 0;
5086 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
5087 r_shadow_prepasslightingdiffusefbo = 0;
5089 if (r_shadow_prepassgeometrydepthbuffer)
5090 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
5091 r_shadow_prepassgeometrydepthbuffer = NULL;
5093 if (r_shadow_prepassgeometrynormalmaptexture)
5094 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
5095 r_shadow_prepassgeometrynormalmaptexture = NULL;
5097 if (r_shadow_prepasslightingdiffusetexture)
5098 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
5099 r_shadow_prepasslightingdiffusetexture = NULL;
5101 if (r_shadow_prepasslightingspeculartexture)
5102 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
5103 r_shadow_prepasslightingspeculartexture = NULL;
5106 void R_Shadow_DrawPrepass(void)
5110 entity_render_t *ent;
5111 float clearcolor[4];
5113 R_Mesh_ResetTextureState();
5115 GL_ColorMask(1,1,1,1);
5116 GL_BlendFunc(GL_ONE, GL_ZERO);
5119 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5120 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
5121 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
5122 if (r_timereport_active)
5123 R_TimeReport("prepasscleargeom");
5125 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
5126 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
5127 if (r_timereport_active)
5128 R_TimeReport("prepassworld");
5130 for (i = 0;i < r_refdef.scene.numentities;i++)
5132 if (!r_refdef.viewcache.entityvisible[i])
5134 ent = r_refdef.scene.entities[i];
5135 if (ent->model && ent->model->DrawPrepass != NULL)
5136 ent->model->DrawPrepass(ent);
5139 if (r_timereport_active)
5140 R_TimeReport("prepassmodels");
5142 GL_DepthMask(false);
5143 GL_ColorMask(1,1,1,1);
5146 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5147 Vector4Set(clearcolor, 0, 0, 0, 0);
5148 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
5149 if (r_timereport_active)
5150 R_TimeReport("prepassclearlit");
5152 R_Shadow_RenderMode_Begin();
5154 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5155 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5157 R_Shadow_RenderMode_End();
5159 if (r_timereport_active)
5160 R_TimeReport("prepasslights");
5163 #define MAX_SCENELIGHTS 65536
5164 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
5166 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
5168 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
5170 r_shadow_scenemaxlights *= 2;
5171 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
5172 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
5174 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
5178 void R_Shadow_DrawLightSprites(void);
5179 void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
5188 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
5189 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
5190 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
5192 if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
5193 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
5194 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
5195 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
5196 r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) ||
5197 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
5198 r_shadow_shadowmapborder != shadowmapborder ||
5199 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
5200 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
5201 R_Shadow_FreeShadowMaps();
5203 r_shadow_fb_fbo = fbo;
5204 r_shadow_fb_depthtexture = depthtexture;
5205 r_shadow_fb_colortexture = colortexture;
5207 r_shadow_usingshadowmaportho = false;
5209 switch (vid.renderpath)
5211 case RENDERPATH_GL20:
5212 case RENDERPATH_D3D9:
5213 case RENDERPATH_D3D10:
5214 case RENDERPATH_D3D11:
5215 case RENDERPATH_SOFT:
5217 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
5219 r_shadow_usingdeferredprepass = false;
5220 if (r_shadow_prepass_width)
5221 R_Shadow_FreeDeferred();
5222 r_shadow_prepass_width = r_shadow_prepass_height = 0;
5226 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
5228 R_Shadow_FreeDeferred();
5230 r_shadow_usingdeferredprepass = true;
5231 r_shadow_prepass_width = vid.width;
5232 r_shadow_prepass_height = vid.height;
5233 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
5234 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);
5235 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);
5236 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);
5238 // set up the geometry pass fbo (depth + normalmap)
5239 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5240 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5241 // render depth into a renderbuffer and other important properties into the normalmap texture
5243 // set up the lighting pass fbo (diffuse + specular)
5244 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5245 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5246 // render diffuse into one texture and specular into another,
5247 // with depth and normalmap bound as textures,
5248 // with depth bound as attachment as well
5250 // set up the lighting pass fbo (diffuse)
5251 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5252 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5253 // render diffuse into one texture,
5254 // with depth and normalmap bound as textures,
5255 // with depth bound as attachment as well
5259 case RENDERPATH_GL11:
5260 case RENDERPATH_GL13:
5261 case RENDERPATH_GLES1:
5262 case RENDERPATH_GLES2:
5263 r_shadow_usingdeferredprepass = false;
5267 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);
5269 r_shadow_scenenumlights = 0;
5270 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5271 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5272 for (lightindex = 0; lightindex < range; lightindex++)
5274 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5275 if (light && (light->flags & flag))
5277 R_Shadow_PrepareLight(&light->rtlight);
5278 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5281 if (r_refdef.scene.rtdlight)
5283 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5285 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
5286 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
5289 else if (gl_flashblend.integer)
5291 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5293 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
5294 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
5295 VectorScale(rtlight->color, f, rtlight->currentcolor);
5299 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
5300 if (r_shadow_debuglight.integer >= 0)
5302 r_shadow_scenenumlights = 0;
5303 lightindex = r_shadow_debuglight.integer;
5304 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5307 R_Shadow_PrepareLight(&light->rtlight);
5308 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5312 // if we're doing shadowmaps we need to prepare the atlas layout now
5313 if (R_Shadow_ShadowMappingEnabled())
5317 // allocate shadowmaps in the atlas now
5318 // 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...
5319 for (lod = 0; lod < 16; lod++)
5321 int packing_success = 0;
5322 int packing_failure = 0;
5323 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
5324 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
5325 if (r_shadow_shadowmapatlas_modelshadows_size)
5326 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);
5327 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5329 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
5330 int size = rtlight->shadowmapsidesize >> lod;
5332 if (!rtlight->castshadows)
5334 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
5337 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
5338 if (rtlight->cached_numshadowentities_noselfshadow)
5340 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
5342 rtlight->shadowmapatlassidesize = size;
5347 // note down that we failed to pack this one, it will have to disable shadows
5348 rtlight->shadowmapatlassidesize = 0;
5352 // generally everything fits and we stop here on the first iteration
5353 if (packing_failure == 0)
5358 if (r_editlights.integer)
5359 R_Shadow_DrawLightSprites();
5362 void R_Shadow_DrawShadowMaps(void)
5364 R_Shadow_RenderMode_Begin();
5365 R_Shadow_RenderMode_ActiveLight(NULL);
5367 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
5368 R_Shadow_ClearShadowMapTexture();
5370 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
5371 if (r_shadow_shadowmapatlas_modelshadows_size)
5373 R_Shadow_DrawModelShadowMaps();
5374 // don't let sound skip if going slow
5375 if (r_refdef.scene.extraupdate)
5379 if (R_Shadow_ShadowMappingEnabled())
5382 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5383 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
5386 R_Shadow_RenderMode_End();
5389 void R_Shadow_DrawLights(void)
5393 R_Shadow_RenderMode_Begin();
5395 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5396 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5398 R_Shadow_RenderMode_End();
5401 #define MAX_MODELSHADOWS 1024
5402 static int r_shadow_nummodelshadows;
5403 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
5405 void R_Shadow_PrepareModelShadows(void)
5408 float scale, size, radius, dot1, dot2;
5409 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5410 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
5411 entity_render_t *ent;
5413 r_shadow_nummodelshadows = 0;
5414 r_shadow_shadowmapatlas_modelshadows_size = 0;
5416 if (!r_refdef.scene.numentities || r_refdef.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
5419 switch (r_shadow_shadowmode)
5421 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
5422 if (r_shadows.integer >= 2)
5425 case R_SHADOW_SHADOWMODE_STENCIL:
5428 for (i = 0; i < r_refdef.scene.numentities; i++)
5430 ent = r_refdef.scene.entities[i];
5431 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5433 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5435 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5436 R_AnimCache_GetEntity(ent, false, false);
5444 size = 2 * r_shadow_shadowmapmaxsize;
5445 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
5446 radius = 0.5f * size / scale;
5448 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5449 VectorCopy(prvmshadowdir, shadowdir);
5450 VectorNormalize(shadowdir);
5451 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5452 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5453 if (fabs(dot1) <= fabs(dot2))
5454 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5456 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5457 VectorNormalize(shadowforward);
5458 CrossProduct(shadowdir, shadowforward, shadowright);
5459 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5460 VectorCopy(prvmshadowfocus, shadowfocus);
5461 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5462 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5463 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5464 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5465 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5467 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5469 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5470 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5471 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5472 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5473 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5474 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5476 for (i = 0; i < r_refdef.scene.numentities; i++)
5478 ent = r_refdef.scene.entities[i];
5479 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
5481 // cast shadows from anything of the map (submodels are optional)
5482 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5484 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5486 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5487 R_AnimCache_GetEntity(ent, false, false);
5491 if (r_shadow_nummodelshadows)
5493 r_shadow_shadowmapatlas_modelshadows_x = 0;
5494 r_shadow_shadowmapatlas_modelshadows_y = 0;
5495 r_shadow_shadowmapatlas_modelshadows_size = size;
5499 static void R_Shadow_DrawModelShadowMaps(void)
5502 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
5503 entity_render_t *ent;
5504 vec3_t relativelightorigin;
5505 vec3_t relativelightdirection, relativeforward, relativeright;
5506 vec3_t relativeshadowmins, relativeshadowmaxs;
5507 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
5508 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5510 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
5511 r_viewport_t viewport;
5513 size = r_shadow_shadowmapatlas_modelshadows_size;
5514 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
5515 radius = 0.5f / scale;
5516 nearclip = -r_shadows_throwdistance.value;
5517 farclip = r_shadows_throwdistance.value;
5518 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);
5520 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
5521 r_shadow_modelshadowmap_parameters[0] = size;
5522 r_shadow_modelshadowmap_parameters[1] = size;
5523 r_shadow_modelshadowmap_parameters[2] = 1.0;
5524 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
5525 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
5526 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
5527 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
5528 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
5529 r_shadow_usingshadowmaportho = true;
5531 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5532 VectorCopy(prvmshadowdir, shadowdir);
5533 VectorNormalize(shadowdir);
5534 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5535 VectorCopy(prvmshadowfocus, shadowfocus);
5536 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5537 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5538 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5539 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5540 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5541 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5542 if (fabs(dot1) <= fabs(dot2))
5543 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5545 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5546 VectorNormalize(shadowforward);
5547 VectorM(scale, shadowforward, &m[0]);
5548 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5550 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
5551 CrossProduct(shadowdir, shadowforward, shadowright);
5552 VectorM(scale, shadowright, &m[4]);
5553 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
5554 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
5555 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
5556 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
5557 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
5558 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);
5559 R_SetViewport(&viewport);
5561 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5563 // render into a slightly restricted region so that the borders of the
5564 // shadowmap area fade away, rather than streaking across everything
5565 // outside the usable area
5566 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
5568 for (i = 0;i < r_shadow_nummodelshadows;i++)
5570 ent = r_shadow_modelshadows[i];
5571 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5572 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
5573 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5574 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
5575 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
5576 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5577 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5578 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5579 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5580 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5581 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5582 RSurf_ActiveModelEntity(ent, false, false, false);
5583 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
5584 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5590 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
5592 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
5594 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
5595 Cvar_SetValueQuick(&r_test, 0);
5600 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
5601 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
5602 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
5603 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
5604 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
5605 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
5607 switch (vid.renderpath)
5609 case RENDERPATH_GL11:
5610 case RENDERPATH_GL13:
5611 case RENDERPATH_GL20:
5612 case RENDERPATH_SOFT:
5613 case RENDERPATH_GLES1:
5614 case RENDERPATH_GLES2:
5616 case RENDERPATH_D3D9:
5617 case RENDERPATH_D3D10:
5618 case RENDERPATH_D3D11:
5619 #ifdef MATRIX4x4_OPENGLORIENTATION
5620 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5621 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
5622 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
5623 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
5625 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5626 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
5627 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
5628 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
5634 void R_Shadow_DrawModelShadows(void)
5637 float relativethrowdistance;
5638 entity_render_t *ent;
5639 vec3_t relativelightorigin;
5640 vec3_t relativelightdirection;
5641 vec3_t relativeshadowmins, relativeshadowmaxs;
5642 vec3_t tmp, shadowdir;
5643 prvm_vec3_t prvmshadowdir;
5645 if (!r_shadow_nummodelshadows || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
5648 R_ResetViewRendering3D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5649 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
5650 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5651 R_Shadow_RenderMode_Begin();
5652 R_Shadow_RenderMode_ActiveLight(NULL);
5653 r_shadow_lightscissor[0] = r_refdef.view.x;
5654 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
5655 r_shadow_lightscissor[2] = r_refdef.view.width;
5656 r_shadow_lightscissor[3] = r_refdef.view.height;
5657 R_Shadow_RenderMode_StencilShadowVolumes(false);
5660 if (r_shadows.integer == 2)
5662 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5663 VectorCopy(prvmshadowdir, shadowdir);
5664 VectorNormalize(shadowdir);
5667 R_Shadow_ClearStencil();
5669 for (i = 0;i < r_shadow_nummodelshadows;i++)
5671 ent = r_shadow_modelshadows[i];
5673 // cast shadows from anything of the map (submodels are optional)
5674 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5675 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
5676 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
5677 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
5678 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5681 if(ent->entitynumber != 0)
5683 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
5685 // FIXME handle this
5686 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5690 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
5691 int entnum, entnum2, recursion;
5692 entnum = entnum2 = ent->entitynumber;
5693 for(recursion = 32; recursion > 0; --recursion)
5695 entnum2 = cl.entities[entnum].state_current.tagentity;
5696 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
5701 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
5703 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
5704 // transform into modelspace of OUR entity
5705 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
5706 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
5709 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5713 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5716 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
5717 RSurf_ActiveModelEntity(ent, false, false, false);
5718 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
5719 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5722 // not really the right mode, but this will disable any silly stencil features
5723 R_Shadow_RenderMode_End();
5725 // set up ortho view for rendering this pass
5726 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5727 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5728 //GL_ScissorTest(true);
5729 //R_EntityMatrix(&identitymatrix);
5730 //R_Mesh_ResetTextureState();
5731 R_ResetViewRendering2D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5733 // set up a darkening blend on shadowed areas
5734 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5735 //GL_DepthRange(0, 1);
5736 //GL_DepthTest(false);
5737 //GL_DepthMask(false);
5738 //GL_PolygonOffset(0, 0);CHECKGLERROR
5739 GL_Color(0, 0, 0, r_shadows_darken.value);
5740 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5741 //GL_DepthFunc(GL_ALWAYS);
5742 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5744 // apply the blend to the shadowed areas
5745 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5746 R_SetupShader_Generic_NoTexture(false, true);
5747 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5749 // restore the viewport
5750 R_SetViewport(&r_refdef.view.viewport);
5752 // restore other state to normal
5753 //R_Shadow_RenderMode_End();
5756 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5759 vec3_t centerorigin;
5760 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5763 // if it's too close, skip it
5764 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5766 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5769 if (usequery && r_numqueries + 2 <= r_maxqueries)
5771 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5772 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5773 // 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
5774 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5776 switch(vid.renderpath)
5778 case RENDERPATH_GL11:
5779 case RENDERPATH_GL13:
5780 case RENDERPATH_GL20:
5781 case RENDERPATH_GLES1:
5782 case RENDERPATH_GLES2:
5783 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5785 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5786 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5787 GL_DepthFunc(GL_ALWAYS);
5788 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5789 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5790 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5791 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5792 GL_DepthFunc(GL_LEQUAL);
5793 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5794 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5795 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5796 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5797 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5801 case RENDERPATH_D3D9:
5802 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5804 case RENDERPATH_D3D10:
5805 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5807 case RENDERPATH_D3D11:
5808 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5810 case RENDERPATH_SOFT:
5811 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5815 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5818 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5820 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5823 unsigned int occlude = 0;
5824 GLint allpixels = 0, visiblepixels = 0;
5826 // now we have to check the query result
5827 if (rtlight->corona_queryindex_visiblepixels)
5829 switch(vid.renderpath)
5831 case RENDERPATH_GL11:
5832 case RENDERPATH_GL13:
5833 case RENDERPATH_GL20:
5834 case RENDERPATH_GLES1:
5835 case RENDERPATH_GLES2:
5836 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5838 // See if we can use the GPU-side method to prevent implicit sync
5839 if (vid.support.arb_query_buffer_object) {
5840 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
5841 if (!r_shadow_occlusion_buf) {
5842 qglGenBuffersARB(1, &r_shadow_occlusion_buf);
5843 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5844 qglBufferDataARB(GL_QUERY_BUFFER_ARB, 8, NULL, GL_DYNAMIC_COPY);
5846 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5848 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(0));
5849 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4));
5850 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
5851 occlude = MATERIALFLAG_OCCLUDE;
5853 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5854 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5855 if (visiblepixels < 1 || allpixels < 1)
5857 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5859 cscale *= rtlight->corona_visibility;
5865 case RENDERPATH_D3D9:
5866 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5868 case RENDERPATH_D3D10:
5869 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5871 case RENDERPATH_D3D11:
5872 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5874 case RENDERPATH_SOFT:
5875 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5883 // FIXME: these traces should scan all render entities instead of cl.world
5884 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)
5887 VectorScale(rtlight->currentcolor, cscale, color);
5888 if (VectorLength(color) > (1.0f / 256.0f))
5891 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
5894 VectorNegate(color, color);
5895 GL_BlendEquationSubtract(true);
5897 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5898 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);
5899 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
5901 GL_BlendEquationSubtract(false);
5905 void R_Shadow_DrawCoronas(void)
5908 qboolean usequery = false;
5913 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
5915 if (r_fb.water.renderingscene)
5917 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5918 R_EntityMatrix(&identitymatrix);
5920 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5922 // check occlusion of coronas
5923 // use GL_ARB_occlusion_query if available
5924 // otherwise use raytraces
5926 switch (vid.renderpath)
5928 case RENDERPATH_GL11:
5929 case RENDERPATH_GL13:
5930 case RENDERPATH_GL20:
5931 case RENDERPATH_GLES1:
5932 case RENDERPATH_GLES2:
5933 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
5934 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5937 GL_ColorMask(0,0,0,0);
5938 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
5939 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
5942 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
5943 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
5945 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
5948 RSurf_ActiveWorldEntity();
5949 GL_BlendFunc(GL_ONE, GL_ZERO);
5950 GL_CullFace(GL_NONE);
5951 GL_DepthMask(false);
5952 GL_DepthRange(0, 1);
5953 GL_PolygonOffset(0, 0);
5955 R_Mesh_ResetTextureState();
5956 R_SetupShader_Generic_NoTexture(false, false);
5960 case RENDERPATH_D3D9:
5962 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5964 case RENDERPATH_D3D10:
5965 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5967 case RENDERPATH_D3D11:
5968 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5970 case RENDERPATH_SOFT:
5972 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5975 for (lightindex = 0;lightindex < range;lightindex++)
5977 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5980 rtlight = &light->rtlight;
5981 rtlight->corona_visibility = 0;
5982 rtlight->corona_queryindex_visiblepixels = 0;
5983 rtlight->corona_queryindex_allpixels = 0;
5984 if (!(rtlight->flags & flag))
5986 if (rtlight->corona <= 0)
5988 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
5990 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5992 for (i = 0;i < r_refdef.scene.numlights;i++)
5994 rtlight = r_refdef.scene.lights[i];
5995 rtlight->corona_visibility = 0;
5996 rtlight->corona_queryindex_visiblepixels = 0;
5997 rtlight->corona_queryindex_allpixels = 0;
5998 if (!(rtlight->flags & flag))
6000 if (rtlight->corona <= 0)
6002 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6005 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
6007 // now draw the coronas using the query data for intensity info
6008 for (lightindex = 0;lightindex < range;lightindex++)
6010 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6013 rtlight = &light->rtlight;
6014 if (rtlight->corona_visibility <= 0)
6016 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6018 for (i = 0;i < r_refdef.scene.numlights;i++)
6020 rtlight = r_refdef.scene.lights[i];
6021 if (rtlight->corona_visibility <= 0)
6023 if (gl_flashblend.integer)
6024 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
6026 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6032 static dlight_t *R_Shadow_NewWorldLight(void)
6034 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
6037 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)
6041 // 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
6043 // validate parameters
6047 // copy to light properties
6048 VectorCopy(origin, light->origin);
6049 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
6050 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
6051 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
6053 light->color[0] = max(color[0], 0);
6054 light->color[1] = max(color[1], 0);
6055 light->color[2] = max(color[2], 0);
6057 light->color[0] = color[0];
6058 light->color[1] = color[1];
6059 light->color[2] = color[2];
6060 light->radius = max(radius, 0);
6061 light->style = style;
6062 light->shadow = shadowenable;
6063 light->corona = corona;
6064 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
6065 light->coronasizescale = coronasizescale;
6066 light->ambientscale = ambientscale;
6067 light->diffusescale = diffusescale;
6068 light->specularscale = specularscale;
6069 light->flags = flags;
6071 // update renderable light data
6072 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
6073 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);
6076 static void R_Shadow_FreeWorldLight(dlight_t *light)
6078 if (r_shadow_selectedlight == light)
6079 r_shadow_selectedlight = NULL;
6080 R_RTLight_Uncompile(&light->rtlight);
6081 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
6084 void R_Shadow_ClearWorldLights(void)
6088 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6089 for (lightindex = 0;lightindex < range;lightindex++)
6091 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6093 R_Shadow_FreeWorldLight(light);
6095 r_shadow_selectedlight = NULL;
6098 static void R_Shadow_SelectLight(dlight_t *light)
6100 if (r_shadow_selectedlight)
6101 r_shadow_selectedlight->selected = false;
6102 r_shadow_selectedlight = light;
6103 if (r_shadow_selectedlight)
6104 r_shadow_selectedlight->selected = true;
6107 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6109 // this is never batched (there can be only one)
6111 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
6112 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6113 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6116 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6121 skinframe_t *skinframe;
6124 // this is never batched (due to the ent parameter changing every time)
6125 // so numsurfaces == 1 and surfacelist[0] == lightnumber
6126 const dlight_t *light = (dlight_t *)ent;
6129 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
6132 VectorScale(light->color, intensity, spritecolor);
6133 if (VectorLength(spritecolor) < 0.1732f)
6134 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
6135 if (VectorLength(spritecolor) > 1.0f)
6136 VectorNormalize(spritecolor);
6138 // draw light sprite
6139 if (light->cubemapname[0] && !light->shadow)
6140 skinframe = r_editlights_sprcubemapnoshadowlight;
6141 else if (light->cubemapname[0])
6142 skinframe = r_editlights_sprcubemaplight;
6143 else if (!light->shadow)
6144 skinframe = r_editlights_sprnoshadowlight;
6146 skinframe = r_editlights_sprlight;
6148 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);
6149 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6151 // draw selection sprite if light is selected
6152 if (light->selected)
6154 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6155 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6156 // VorteX todo: add normalmode/realtime mode light overlay sprites?
6160 void R_Shadow_DrawLightSprites(void)
6164 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6165 for (lightindex = 0;lightindex < range;lightindex++)
6167 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6169 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
6171 if (!r_editlights_lockcursor)
6172 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
6175 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
6180 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6181 if (lightindex >= range)
6183 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6186 rtlight = &light->rtlight;
6187 //if (!(rtlight->flags & flag))
6189 VectorCopy(rtlight->shadoworigin, origin);
6190 *radius = rtlight->radius;
6191 VectorCopy(rtlight->color, color);
6195 static void R_Shadow_SelectLightInView(void)
6197 float bestrating, rating, temp[3];
6201 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6205 if (r_editlights_lockcursor)
6207 for (lightindex = 0;lightindex < range;lightindex++)
6209 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6212 VectorSubtract(light->origin, r_refdef.view.origin, temp);
6213 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
6216 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
6217 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)
6219 bestrating = rating;
6224 R_Shadow_SelectLight(best);
6227 void R_Shadow_LoadWorldLights(void)
6229 int n, a, style, shadow, flags;
6230 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
6231 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
6232 if (cl.worldmodel == NULL)
6234 Con_Print("No map loaded.\n");
6237 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6238 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6248 for (;COM_Parse(t, true) && strcmp(
6249 if (COM_Parse(t, true))
6251 if (com_token[0] == '!')
6254 origin[0] = atof(com_token+1);
6257 origin[0] = atof(com_token);
6262 while (*s && *s != '\n' && *s != '\r')
6268 // check for modifier flags
6275 #if _MSC_VER >= 1400
6276 #define sscanf sscanf_s
6278 cubemapname[sizeof(cubemapname)-1] = 0;
6279 #if MAX_QPATH != 128
6280 #error update this code if MAX_QPATH changes
6282 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
6283 #if _MSC_VER >= 1400
6284 , sizeof(cubemapname)
6286 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
6289 flags = LIGHTFLAG_REALTIMEMODE;
6297 coronasizescale = 0.25f;
6299 VectorClear(angles);
6302 if (a < 9 || !strcmp(cubemapname, "\"\""))
6304 // remove quotes on cubemapname
6305 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
6308 namelen = strlen(cubemapname) - 2;
6309 memmove(cubemapname, cubemapname + 1, namelen);
6310 cubemapname[namelen] = '\0';
6314 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);
6317 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6325 Con_Printf("invalid rtlights file \"%s\"\n", name);
6326 Mem_Free(lightsstring);
6330 void R_Shadow_SaveWorldLights(void)
6334 size_t bufchars, bufmaxchars;
6336 char name[MAX_QPATH];
6337 char line[MAX_INPUTLINE];
6338 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
6339 // I hate lines which are 3 times my screen size :( --blub
6342 if (cl.worldmodel == NULL)
6344 Con_Print("No map loaded.\n");
6347 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6348 bufchars = bufmaxchars = 0;
6350 for (lightindex = 0;lightindex < range;lightindex++)
6352 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6355 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
6356 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);
6357 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
6358 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]);
6360 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);
6361 if (bufchars + strlen(line) > bufmaxchars)
6363 bufmaxchars = bufchars + strlen(line) + 2048;
6365 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
6369 memcpy(buf, oldbuf, bufchars);
6375 memcpy(buf + bufchars, line, strlen(line));
6376 bufchars += strlen(line);
6380 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
6385 void R_Shadow_LoadLightsFile(void)
6388 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
6389 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
6390 if (cl.worldmodel == NULL)
6392 Con_Print("No map loaded.\n");
6395 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
6396 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6404 while (*s && *s != '\n' && *s != '\r')
6410 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);
6414 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);
6417 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
6418 radius = bound(15, radius, 4096);
6419 VectorScale(color, (2.0f / (8388608.0f)), color);
6420 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6428 Con_Printf("invalid lights file \"%s\"\n", name);
6429 Mem_Free(lightsstring);
6433 // tyrlite/hmap2 light types in the delay field
6434 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
6436 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
6448 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
6449 char key[256], value[MAX_INPUTLINE];
6452 if (cl.worldmodel == NULL)
6454 Con_Print("No map loaded.\n");
6457 // try to load a .ent file first
6458 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
6459 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
6460 // and if that is not found, fall back to the bsp file entity string
6462 data = cl.worldmodel->brush.entities;
6465 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
6467 type = LIGHTTYPE_MINUSX;
6468 origin[0] = origin[1] = origin[2] = 0;
6469 originhack[0] = originhack[1] = originhack[2] = 0;
6470 angles[0] = angles[1] = angles[2] = 0;
6471 color[0] = color[1] = color[2] = 1;
6472 light[0] = light[1] = light[2] = 1;light[3] = 300;
6473 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
6483 if (!COM_ParseToken_Simple(&data, false, false, true))
6485 if (com_token[0] == '}')
6486 break; // end of entity
6487 if (com_token[0] == '_')
6488 strlcpy(key, com_token + 1, sizeof(key));
6490 strlcpy(key, com_token, sizeof(key));
6491 while (key[strlen(key)-1] == ' ') // remove trailing spaces
6492 key[strlen(key)-1] = 0;
6493 if (!COM_ParseToken_Simple(&data, false, false, true))
6495 strlcpy(value, com_token, sizeof(value));
6497 // now that we have the key pair worked out...
6498 if (!strcmp("light", key))
6500 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
6504 light[0] = vec[0] * (1.0f / 256.0f);
6505 light[1] = vec[0] * (1.0f / 256.0f);
6506 light[2] = vec[0] * (1.0f / 256.0f);
6512 light[0] = vec[0] * (1.0f / 255.0f);
6513 light[1] = vec[1] * (1.0f / 255.0f);
6514 light[2] = vec[2] * (1.0f / 255.0f);
6518 else if (!strcmp("delay", key))
6520 else if (!strcmp("origin", key))
6521 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
6522 else if (!strcmp("angle", key))
6523 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
6524 else if (!strcmp("angles", key))
6525 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
6526 else if (!strcmp("color", key))
6527 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
6528 else if (!strcmp("wait", key))
6529 fadescale = atof(value);
6530 else if (!strcmp("classname", key))
6532 if (!strncmp(value, "light", 5))
6535 if (!strcmp(value, "light_fluoro"))
6540 overridecolor[0] = 1;
6541 overridecolor[1] = 1;
6542 overridecolor[2] = 1;
6544 if (!strcmp(value, "light_fluorospark"))
6549 overridecolor[0] = 1;
6550 overridecolor[1] = 1;
6551 overridecolor[2] = 1;
6553 if (!strcmp(value, "light_globe"))
6558 overridecolor[0] = 1;
6559 overridecolor[1] = 0.8;
6560 overridecolor[2] = 0.4;
6562 if (!strcmp(value, "light_flame_large_yellow"))
6567 overridecolor[0] = 1;
6568 overridecolor[1] = 0.5;
6569 overridecolor[2] = 0.1;
6571 if (!strcmp(value, "light_flame_small_yellow"))
6576 overridecolor[0] = 1;
6577 overridecolor[1] = 0.5;
6578 overridecolor[2] = 0.1;
6580 if (!strcmp(value, "light_torch_small_white"))
6585 overridecolor[0] = 1;
6586 overridecolor[1] = 0.5;
6587 overridecolor[2] = 0.1;
6589 if (!strcmp(value, "light_torch_small_walltorch"))
6594 overridecolor[0] = 1;
6595 overridecolor[1] = 0.5;
6596 overridecolor[2] = 0.1;
6600 else if (!strcmp("style", key))
6601 style = atoi(value);
6602 else if (!strcmp("skin", key))
6603 skin = (int)atof(value);
6604 else if (!strcmp("pflags", key))
6605 pflags = (int)atof(value);
6606 //else if (!strcmp("effects", key))
6607 // effects = (int)atof(value);
6608 else if (cl.worldmodel->type == mod_brushq3)
6610 if (!strcmp("scale", key))
6611 lightscale = atof(value);
6612 if (!strcmp("fade", key))
6613 fadescale = atof(value);
6618 if (lightscale <= 0)
6622 if (color[0] == color[1] && color[0] == color[2])
6624 color[0] *= overridecolor[0];
6625 color[1] *= overridecolor[1];
6626 color[2] *= overridecolor[2];
6628 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
6629 color[0] = color[0] * light[0];
6630 color[1] = color[1] * light[1];
6631 color[2] = color[2] * light[2];
6634 case LIGHTTYPE_MINUSX:
6636 case LIGHTTYPE_RECIPX:
6638 VectorScale(color, (1.0f / 16.0f), color);
6640 case LIGHTTYPE_RECIPXX:
6642 VectorScale(color, (1.0f / 16.0f), color);
6645 case LIGHTTYPE_NONE:
6649 case LIGHTTYPE_MINUSXX:
6652 VectorAdd(origin, originhack, origin);
6654 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);
6657 Mem_Free(entfiledata);
6661 static void R_Shadow_SetCursorLocationForView(void)
6664 vec3_t dest, endpos;
6666 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
6667 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true);
6668 if (trace.fraction < 1)
6670 dist = trace.fraction * r_editlights_cursordistance.value;
6671 push = r_editlights_cursorpushback.value;
6675 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
6676 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
6680 VectorClear( endpos );
6682 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6683 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6684 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6687 void R_Shadow_UpdateWorldLightSelection(void)
6689 if (r_editlights.integer)
6691 R_Shadow_SetCursorLocationForView();
6692 R_Shadow_SelectLightInView();
6695 R_Shadow_SelectLight(NULL);
6698 static void R_Shadow_EditLights_Clear_f(void)
6700 R_Shadow_ClearWorldLights();
6703 void R_Shadow_EditLights_Reload_f(void)
6707 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
6708 R_Shadow_ClearWorldLights();
6709 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
6711 R_Shadow_LoadWorldLights();
6712 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6713 R_Shadow_LoadLightsFile();
6715 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
6717 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6718 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6722 static void R_Shadow_EditLights_Save_f(void)
6726 R_Shadow_SaveWorldLights();
6729 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6731 R_Shadow_ClearWorldLights();
6732 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6735 static void R_Shadow_EditLights_ImportLightsFile_f(void)
6737 R_Shadow_ClearWorldLights();
6738 R_Shadow_LoadLightsFile();
6741 static void R_Shadow_EditLights_Spawn_f(void)
6744 if (!r_editlights.integer)
6746 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6749 if (Cmd_Argc() != 1)
6751 Con_Print("r_editlights_spawn does not take parameters\n");
6754 color[0] = color[1] = color[2] = 1;
6755 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6758 static void R_Shadow_EditLights_Edit_f(void)
6760 vec3_t origin, angles, color;
6761 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6762 int style, shadows, flags, normalmode, realtimemode;
6763 char cubemapname[MAX_INPUTLINE];
6764 if (!r_editlights.integer)
6766 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6769 if (!r_shadow_selectedlight)
6771 Con_Print("No selected light.\n");
6774 VectorCopy(r_shadow_selectedlight->origin, origin);
6775 VectorCopy(r_shadow_selectedlight->angles, angles);
6776 VectorCopy(r_shadow_selectedlight->color, color);
6777 radius = r_shadow_selectedlight->radius;
6778 style = r_shadow_selectedlight->style;
6779 if (r_shadow_selectedlight->cubemapname)
6780 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6783 shadows = r_shadow_selectedlight->shadow;
6784 corona = r_shadow_selectedlight->corona;
6785 coronasizescale = r_shadow_selectedlight->coronasizescale;
6786 ambientscale = r_shadow_selectedlight->ambientscale;
6787 diffusescale = r_shadow_selectedlight->diffusescale;
6788 specularscale = r_shadow_selectedlight->specularscale;
6789 flags = r_shadow_selectedlight->flags;
6790 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6791 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6792 if (!strcmp(Cmd_Argv(1), "origin"))
6794 if (Cmd_Argc() != 5)
6796 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6799 origin[0] = atof(Cmd_Argv(2));
6800 origin[1] = atof(Cmd_Argv(3));
6801 origin[2] = atof(Cmd_Argv(4));
6803 else if (!strcmp(Cmd_Argv(1), "originscale"))
6805 if (Cmd_Argc() != 5)
6807 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6810 origin[0] *= atof(Cmd_Argv(2));
6811 origin[1] *= atof(Cmd_Argv(3));
6812 origin[2] *= atof(Cmd_Argv(4));
6814 else if (!strcmp(Cmd_Argv(1), "originx"))
6816 if (Cmd_Argc() != 3)
6818 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6821 origin[0] = atof(Cmd_Argv(2));
6823 else if (!strcmp(Cmd_Argv(1), "originy"))
6825 if (Cmd_Argc() != 3)
6827 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6830 origin[1] = atof(Cmd_Argv(2));
6832 else if (!strcmp(Cmd_Argv(1), "originz"))
6834 if (Cmd_Argc() != 3)
6836 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6839 origin[2] = atof(Cmd_Argv(2));
6841 else if (!strcmp(Cmd_Argv(1), "move"))
6843 if (Cmd_Argc() != 5)
6845 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6848 origin[0] += atof(Cmd_Argv(2));
6849 origin[1] += atof(Cmd_Argv(3));
6850 origin[2] += atof(Cmd_Argv(4));
6852 else if (!strcmp(Cmd_Argv(1), "movex"))
6854 if (Cmd_Argc() != 3)
6856 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6859 origin[0] += atof(Cmd_Argv(2));
6861 else if (!strcmp(Cmd_Argv(1), "movey"))
6863 if (Cmd_Argc() != 3)
6865 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6868 origin[1] += atof(Cmd_Argv(2));
6870 else if (!strcmp(Cmd_Argv(1), "movez"))
6872 if (Cmd_Argc() != 3)
6874 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6877 origin[2] += atof(Cmd_Argv(2));
6879 else if (!strcmp(Cmd_Argv(1), "angles"))
6881 if (Cmd_Argc() != 5)
6883 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6886 angles[0] = atof(Cmd_Argv(2));
6887 angles[1] = atof(Cmd_Argv(3));
6888 angles[2] = atof(Cmd_Argv(4));
6890 else if (!strcmp(Cmd_Argv(1), "anglesx"))
6892 if (Cmd_Argc() != 3)
6894 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6897 angles[0] = atof(Cmd_Argv(2));
6899 else if (!strcmp(Cmd_Argv(1), "anglesy"))
6901 if (Cmd_Argc() != 3)
6903 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6906 angles[1] = atof(Cmd_Argv(2));
6908 else if (!strcmp(Cmd_Argv(1), "anglesz"))
6910 if (Cmd_Argc() != 3)
6912 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6915 angles[2] = atof(Cmd_Argv(2));
6917 else if (!strcmp(Cmd_Argv(1), "color"))
6919 if (Cmd_Argc() != 5)
6921 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
6924 color[0] = atof(Cmd_Argv(2));
6925 color[1] = atof(Cmd_Argv(3));
6926 color[2] = atof(Cmd_Argv(4));
6928 else if (!strcmp(Cmd_Argv(1), "radius"))
6930 if (Cmd_Argc() != 3)
6932 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6935 radius = atof(Cmd_Argv(2));
6937 else if (!strcmp(Cmd_Argv(1), "colorscale"))
6939 if (Cmd_Argc() == 3)
6941 double scale = atof(Cmd_Argv(2));
6948 if (Cmd_Argc() != 5)
6950 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
6953 color[0] *= atof(Cmd_Argv(2));
6954 color[1] *= atof(Cmd_Argv(3));
6955 color[2] *= atof(Cmd_Argv(4));
6958 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
6960 if (Cmd_Argc() != 3)
6962 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6965 radius *= atof(Cmd_Argv(2));
6967 else if (!strcmp(Cmd_Argv(1), "style"))
6969 if (Cmd_Argc() != 3)
6971 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6974 style = atoi(Cmd_Argv(2));
6976 else if (!strcmp(Cmd_Argv(1), "cubemap"))
6980 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6983 if (Cmd_Argc() == 3)
6984 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
6988 else if (!strcmp(Cmd_Argv(1), "shadows"))
6990 if (Cmd_Argc() != 3)
6992 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6995 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6997 else if (!strcmp(Cmd_Argv(1), "corona"))
6999 if (Cmd_Argc() != 3)
7001 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7004 corona = atof(Cmd_Argv(2));
7006 else if (!strcmp(Cmd_Argv(1), "coronasize"))
7008 if (Cmd_Argc() != 3)
7010 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7013 coronasizescale = atof(Cmd_Argv(2));
7015 else if (!strcmp(Cmd_Argv(1), "ambient"))
7017 if (Cmd_Argc() != 3)
7019 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7022 ambientscale = atof(Cmd_Argv(2));
7024 else if (!strcmp(Cmd_Argv(1), "diffuse"))
7026 if (Cmd_Argc() != 3)
7028 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7031 diffusescale = atof(Cmd_Argv(2));
7033 else if (!strcmp(Cmd_Argv(1), "specular"))
7035 if (Cmd_Argc() != 3)
7037 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7040 specularscale = atof(Cmd_Argv(2));
7042 else if (!strcmp(Cmd_Argv(1), "normalmode"))
7044 if (Cmd_Argc() != 3)
7046 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7049 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7051 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
7053 if (Cmd_Argc() != 3)
7055 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7058 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7062 Con_Print("usage: r_editlights_edit [property] [value]\n");
7063 Con_Print("Selected light's properties:\n");
7064 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7065 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7066 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7067 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
7068 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
7069 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
7070 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
7071 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
7072 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
7073 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
7074 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
7075 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
7076 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
7077 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
7080 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
7081 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
7084 static void R_Shadow_EditLights_EditAll_f(void)
7087 dlight_t *light, *oldselected;
7090 if (!r_editlights.integer)
7092 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
7096 oldselected = r_shadow_selectedlight;
7097 // EditLights doesn't seem to have a "remove" command or something so:
7098 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7099 for (lightindex = 0;lightindex < range;lightindex++)
7101 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7104 R_Shadow_SelectLight(light);
7105 R_Shadow_EditLights_Edit_f();
7107 // return to old selected (to not mess editing once selection is locked)
7108 R_Shadow_SelectLight(oldselected);
7111 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
7113 int lightnumber, lightcount;
7114 size_t lightindex, range;
7119 if (!r_editlights.integer)
7122 // update cvars so QC can query them
7123 if (r_shadow_selectedlight)
7125 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7126 Cvar_SetQuick(&r_editlights_current_origin, temp);
7127 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7128 Cvar_SetQuick(&r_editlights_current_angles, temp);
7129 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7130 Cvar_SetQuick(&r_editlights_current_color, temp);
7131 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
7132 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
7133 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
7134 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
7135 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
7136 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
7137 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
7138 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
7139 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
7140 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
7141 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
7144 // draw properties on screen
7145 if (!r_editlights_drawproperties.integer)
7147 x = vid_conwidth.value - 240;
7149 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
7152 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7153 for (lightindex = 0;lightindex < range;lightindex++)
7155 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7158 if (light == r_shadow_selectedlight)
7159 lightnumber = (int)lightindex;
7162 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;
7163 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;
7165 if (r_shadow_selectedlight == NULL)
7167 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;
7168 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;
7169 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;
7170 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;
7171 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;
7172 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;
7173 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;
7174 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;
7175 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;
7176 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;
7177 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;
7178 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;
7179 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;
7180 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;
7181 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;
7184 static void R_Shadow_EditLights_ToggleShadow_f(void)
7186 if (!r_editlights.integer)
7188 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7191 if (!r_shadow_selectedlight)
7193 Con_Print("No selected light.\n");
7196 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);
7199 static void R_Shadow_EditLights_ToggleCorona_f(void)
7201 if (!r_editlights.integer)
7203 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7206 if (!r_shadow_selectedlight)
7208 Con_Print("No selected light.\n");
7211 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);
7214 static void R_Shadow_EditLights_Remove_f(void)
7216 if (!r_editlights.integer)
7218 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
7221 if (!r_shadow_selectedlight)
7223 Con_Print("No selected light.\n");
7226 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
7227 r_shadow_selectedlight = NULL;
7230 static void R_Shadow_EditLights_Help_f(void)
7233 "Documentation on r_editlights system:\n"
7235 "r_editlights : enable/disable editing mode\n"
7236 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
7237 "r_editlights_cursorpushback : push back cursor this far from surface\n"
7238 "r_editlights_cursorpushoff : push cursor off surface this far\n"
7239 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
7240 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
7242 "r_editlights_help : this help\n"
7243 "r_editlights_clear : remove all lights\n"
7244 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
7245 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
7246 "r_editlights_save : save to .rtlights file\n"
7247 "r_editlights_spawn : create a light with default settings\n"
7248 "r_editlights_edit command : edit selected light - more documentation below\n"
7249 "r_editlights_remove : remove selected light\n"
7250 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
7251 "r_editlights_importlightentitiesfrommap : reload light entities\n"
7252 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
7254 "origin x y z : set light location\n"
7255 "originx x: set x component of light location\n"
7256 "originy y: set y component of light location\n"
7257 "originz z: set z component of light location\n"
7258 "move x y z : adjust light location\n"
7259 "movex x: adjust x component of light location\n"
7260 "movey y: adjust y component of light location\n"
7261 "movez z: adjust z component of light location\n"
7262 "angles x y z : set light angles\n"
7263 "anglesx x: set x component of light angles\n"
7264 "anglesy y: set y component of light angles\n"
7265 "anglesz z: set z component of light angles\n"
7266 "color r g b : set color of light (can be brighter than 1 1 1)\n"
7267 "radius radius : set radius (size) of light\n"
7268 "colorscale grey : multiply color of light (1 does nothing)\n"
7269 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
7270 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
7271 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
7272 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
7273 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
7274 "cubemap basename : set filter cubemap of light\n"
7275 "shadows 1/0 : turn on/off shadows\n"
7276 "corona n : set corona intensity\n"
7277 "coronasize n : set corona size (0-1)\n"
7278 "ambient n : set ambient intensity (0-1)\n"
7279 "diffuse n : set diffuse intensity (0-1)\n"
7280 "specular n : set specular intensity (0-1)\n"
7281 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
7282 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
7283 "<nothing> : print light properties to console\n"
7287 static void R_Shadow_EditLights_CopyInfo_f(void)
7289 if (!r_editlights.integer)
7291 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
7294 if (!r_shadow_selectedlight)
7296 Con_Print("No selected light.\n");
7299 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
7300 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
7301 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
7302 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
7303 if (r_shadow_selectedlight->cubemapname)
7304 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
7306 r_shadow_bufferlight.cubemapname[0] = 0;
7307 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
7308 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
7309 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
7310 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
7311 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
7312 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
7313 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
7316 static void R_Shadow_EditLights_PasteInfo_f(void)
7318 if (!r_editlights.integer)
7320 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
7323 if (!r_shadow_selectedlight)
7325 Con_Print("No selected light.\n");
7328 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);
7331 static void R_Shadow_EditLights_Lock_f(void)
7333 if (!r_editlights.integer)
7335 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
7338 if (r_editlights_lockcursor)
7340 r_editlights_lockcursor = false;
7343 if (!r_shadow_selectedlight)
7345 Con_Print("No selected light to lock on.\n");
7348 r_editlights_lockcursor = true;
7351 static void R_Shadow_EditLights_Init(void)
7353 Cvar_RegisterVariable(&r_editlights);
7354 Cvar_RegisterVariable(&r_editlights_cursordistance);
7355 Cvar_RegisterVariable(&r_editlights_cursorpushback);
7356 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
7357 Cvar_RegisterVariable(&r_editlights_cursorgrid);
7358 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
7359 Cvar_RegisterVariable(&r_editlights_drawproperties);
7360 Cvar_RegisterVariable(&r_editlights_current_origin);
7361 Cvar_RegisterVariable(&r_editlights_current_angles);
7362 Cvar_RegisterVariable(&r_editlights_current_color);
7363 Cvar_RegisterVariable(&r_editlights_current_radius);
7364 Cvar_RegisterVariable(&r_editlights_current_corona);
7365 Cvar_RegisterVariable(&r_editlights_current_coronasize);
7366 Cvar_RegisterVariable(&r_editlights_current_style);
7367 Cvar_RegisterVariable(&r_editlights_current_shadows);
7368 Cvar_RegisterVariable(&r_editlights_current_cubemap);
7369 Cvar_RegisterVariable(&r_editlights_current_ambient);
7370 Cvar_RegisterVariable(&r_editlights_current_diffuse);
7371 Cvar_RegisterVariable(&r_editlights_current_specular);
7372 Cvar_RegisterVariable(&r_editlights_current_normalmode);
7373 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
7374 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
7375 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
7376 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)");
7377 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
7378 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
7379 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
7380 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)");
7381 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
7382 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
7383 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
7384 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
7385 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
7386 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
7387 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)");
7388 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
7394 =============================================================================
7398 =============================================================================
7401 void R_LightPoint(float *color, const vec3_t p, const int flags)
7403 int i, numlights, flag;
7404 float f, relativepoint[3], dist, dist2, lightradius2;
7409 if (r_fullbright.integer)
7411 VectorSet(color, 1, 1, 1);
7417 if (flags & LP_LIGHTMAP)
7419 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7421 VectorClear(diffuse);
7422 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, color, diffuse, n);
7423 VectorAdd(color, diffuse, color);
7426 VectorSet(color, 1, 1, 1);
7427 color[0] += r_refdef.scene.ambient;
7428 color[1] += r_refdef.scene.ambient;
7429 color[2] += r_refdef.scene.ambient;
7432 if (flags & LP_RTWORLD)
7434 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7435 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7436 for (i = 0; i < numlights; i++)
7438 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7441 light = &dlight->rtlight;
7442 if (!(light->flags & flag))
7445 lightradius2 = light->radius * light->radius;
7446 VectorSubtract(light->shadoworigin, p, relativepoint);
7447 dist2 = VectorLength2(relativepoint);
7448 if (dist2 >= lightradius2)
7450 dist = sqrt(dist2) / light->radius;
7451 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7454 // todo: add to both ambient and diffuse
7455 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)
7456 VectorMA(color, f, light->currentcolor, color);
7459 if (flags & LP_DYNLIGHT)
7462 for (i = 0;i < r_refdef.scene.numlights;i++)
7464 light = r_refdef.scene.lights[i];
7466 lightradius2 = light->radius * light->radius;
7467 VectorSubtract(light->shadoworigin, p, relativepoint);
7468 dist2 = VectorLength2(relativepoint);
7469 if (dist2 >= lightradius2)
7471 dist = sqrt(dist2) / light->radius;
7472 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7475 // todo: add to both ambient and diffuse
7476 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)
7477 VectorMA(color, f, light->color, color);
7482 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
7484 int i, numlights, flag;
7487 float relativepoint[3];
7496 if (r_fullbright.integer)
7498 VectorSet(ambient, 1, 1, 1);
7499 VectorClear(diffuse);
7500 VectorClear(lightdir);
7504 if (flags == LP_LIGHTMAP)
7506 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7507 VectorClear(diffuse);
7508 VectorClear(lightdir);
7509 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7510 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
7512 VectorSet(ambient, 1, 1, 1);
7516 memset(sample, 0, sizeof(sample));
7517 VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7519 if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7522 VectorClear(tempambient);
7524 VectorClear(relativepoint);
7525 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
7526 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
7527 VectorScale(color, r_refdef.lightmapintensity, color);
7528 VectorAdd(sample, tempambient, sample);
7529 VectorMA(sample , 0.5f , color, sample );
7530 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7531 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7532 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7533 // calculate a weighted average light direction as well
7534 intensity = VectorLength(color);
7535 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7538 if (flags & LP_RTWORLD)
7540 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7541 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7542 for (i = 0; i < numlights; i++)
7544 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7547 light = &dlight->rtlight;
7548 if (!(light->flags & flag))
7551 lightradius2 = light->radius * light->radius;
7552 VectorSubtract(light->shadoworigin, p, relativepoint);
7553 dist2 = VectorLength2(relativepoint);
7554 if (dist2 >= lightradius2)
7556 dist = sqrt(dist2) / light->radius;
7557 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
7558 if (intensity <= 0.0f)
7560 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)
7562 // scale down intensity to add to both ambient and diffuse
7563 //intensity *= 0.5f;
7564 VectorNormalize(relativepoint);
7565 VectorScale(light->currentcolor, intensity, color);
7566 VectorMA(sample , 0.5f , color, sample );
7567 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7568 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7569 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7570 // calculate a weighted average light direction as well
7571 intensity *= VectorLength(color);
7572 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7574 // FIXME: sample bouncegrid too!
7577 if (flags & LP_DYNLIGHT)
7580 for (i = 0;i < r_refdef.scene.numlights;i++)
7582 light = r_refdef.scene.lights[i];
7584 lightradius2 = light->radius * light->radius;
7585 VectorSubtract(light->shadoworigin, p, relativepoint);
7586 dist2 = VectorLength2(relativepoint);
7587 if (dist2 >= lightradius2)
7589 dist = sqrt(dist2) / light->radius;
7590 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
7591 if (intensity <= 0.0f)
7593 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)
7595 // scale down intensity to add to both ambient and diffuse
7596 //intensity *= 0.5f;
7597 VectorNormalize(relativepoint);
7598 VectorScale(light->currentcolor, intensity, color);
7599 VectorMA(sample , 0.5f , color, sample );
7600 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7601 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7602 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7603 // calculate a weighted average light direction as well
7604 intensity *= VectorLength(color);
7605 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7609 // calculate the direction we'll use to reduce the sample to a directional light source
7610 VectorCopy(sample + 12, dir);
7611 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
7612 VectorNormalize(dir);
7613 // extract the diffuse color along the chosen direction and scale it
7614 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
7615 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
7616 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
7617 // subtract some of diffuse from ambient
7618 VectorMA(sample, -0.333f, diffuse, ambient);
7619 // store the normalized lightdir
7620 VectorCopy(dir, lightdir);