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_bouncegrid_state.maxsplatpaths = 16384;
555 r_shadow_attenuationgradienttexture = NULL;
556 r_shadow_attenuation2dtexture = NULL;
557 r_shadow_attenuation3dtexture = NULL;
558 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
559 r_shadow_shadowmap2ddepthtexture = NULL;
560 r_shadow_shadowmap2ddepthbuffer = NULL;
561 r_shadow_shadowmapvsdcttexture = NULL;
562 r_shadow_shadowmapmaxsize = 0;
563 r_shadow_shadowmaptexturesize = 0;
564 r_shadow_shadowmapfilterquality = -1;
565 r_shadow_shadowmapdepthbits = 0;
566 r_shadow_shadowmapvsdct = false;
567 r_shadow_shadowmapsampler = false;
568 r_shadow_shadowmappcf = 0;
571 R_Shadow_FreeShadowMaps();
573 r_shadow_texturepool = NULL;
574 r_shadow_filters_texturepool = NULL;
575 R_Shadow_ValidateCvars();
576 R_Shadow_MakeTextures();
577 r_shadow_scenemaxlights = 0;
578 r_shadow_scenenumlights = 0;
579 r_shadow_scenelightlist = NULL;
580 maxshadowtriangles = 0;
581 shadowelements = NULL;
582 maxshadowvertices = 0;
583 shadowvertex3f = NULL;
591 shadowmarklist = NULL;
596 shadowsideslist = NULL;
597 r_shadow_buffer_numleafpvsbytes = 0;
598 r_shadow_buffer_visitingleafpvs = NULL;
599 r_shadow_buffer_leafpvs = NULL;
600 r_shadow_buffer_leaflist = NULL;
601 r_shadow_buffer_numsurfacepvsbytes = 0;
602 r_shadow_buffer_surfacepvs = NULL;
603 r_shadow_buffer_surfacelist = NULL;
604 r_shadow_buffer_surfacesides = NULL;
605 r_shadow_buffer_numshadowtrispvsbytes = 0;
606 r_shadow_buffer_shadowtrispvs = NULL;
607 r_shadow_buffer_numlighttrispvsbytes = 0;
608 r_shadow_buffer_lighttrispvs = NULL;
610 r_shadow_usingdeferredprepass = false;
611 r_shadow_prepass_width = r_shadow_prepass_height = 0;
613 // determine renderpath specific capabilities, we don't need to figure
614 // these out per frame...
615 switch(vid.renderpath)
617 case RENDERPATH_GL20:
618 r_shadow_bouncegrid_state.allowdirectionalshading = true;
619 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
621 case RENDERPATH_GLES2:
622 // for performance reasons, do not use directional shading on GLES devices
623 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
625 // these renderpaths do not currently have the code to display the bouncegrid, so disable it on them...
626 case RENDERPATH_GL11:
627 case RENDERPATH_GL13:
628 case RENDERPATH_GLES1:
629 case RENDERPATH_SOFT:
630 case RENDERPATH_D3D9:
631 case RENDERPATH_D3D10:
632 case RENDERPATH_D3D11:
637 static void R_Shadow_FreeDeferred(void);
638 static void r_shadow_shutdown(void)
641 R_Shadow_UncompileWorldLights();
643 R_Shadow_FreeShadowMaps();
645 r_shadow_usingdeferredprepass = false;
646 if (r_shadow_prepass_width)
647 R_Shadow_FreeDeferred();
648 r_shadow_prepass_width = r_shadow_prepass_height = 0;
651 r_shadow_scenemaxlights = 0;
652 r_shadow_scenenumlights = 0;
653 if (r_shadow_scenelightlist)
654 Mem_Free(r_shadow_scenelightlist);
655 r_shadow_scenelightlist = NULL;
656 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
657 r_shadow_attenuationgradienttexture = NULL;
658 r_shadow_attenuation2dtexture = NULL;
659 r_shadow_attenuation3dtexture = NULL;
660 R_FreeTexturePool(&r_shadow_texturepool);
661 R_FreeTexturePool(&r_shadow_filters_texturepool);
662 maxshadowtriangles = 0;
664 Mem_Free(shadowelements);
665 shadowelements = NULL;
667 Mem_Free(shadowvertex3f);
668 shadowvertex3f = NULL;
671 Mem_Free(vertexupdate);
674 Mem_Free(vertexremap);
680 Mem_Free(shadowmark);
683 Mem_Free(shadowmarklist);
684 shadowmarklist = NULL;
689 Mem_Free(shadowsides);
692 Mem_Free(shadowsideslist);
693 shadowsideslist = NULL;
694 r_shadow_buffer_numleafpvsbytes = 0;
695 if (r_shadow_buffer_visitingleafpvs)
696 Mem_Free(r_shadow_buffer_visitingleafpvs);
697 r_shadow_buffer_visitingleafpvs = NULL;
698 if (r_shadow_buffer_leafpvs)
699 Mem_Free(r_shadow_buffer_leafpvs);
700 r_shadow_buffer_leafpvs = NULL;
701 if (r_shadow_buffer_leaflist)
702 Mem_Free(r_shadow_buffer_leaflist);
703 r_shadow_buffer_leaflist = NULL;
704 r_shadow_buffer_numsurfacepvsbytes = 0;
705 if (r_shadow_buffer_surfacepvs)
706 Mem_Free(r_shadow_buffer_surfacepvs);
707 r_shadow_buffer_surfacepvs = NULL;
708 if (r_shadow_buffer_surfacelist)
709 Mem_Free(r_shadow_buffer_surfacelist);
710 r_shadow_buffer_surfacelist = NULL;
711 if (r_shadow_buffer_surfacesides)
712 Mem_Free(r_shadow_buffer_surfacesides);
713 r_shadow_buffer_surfacesides = NULL;
714 r_shadow_buffer_numshadowtrispvsbytes = 0;
715 if (r_shadow_buffer_shadowtrispvs)
716 Mem_Free(r_shadow_buffer_shadowtrispvs);
717 r_shadow_buffer_numlighttrispvsbytes = 0;
718 if (r_shadow_buffer_lighttrispvs)
719 Mem_Free(r_shadow_buffer_lighttrispvs);
722 static void r_shadow_newmap(void)
724 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
725 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
726 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
727 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
728 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
729 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
730 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
731 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
732 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
733 R_Shadow_EditLights_Reload_f();
736 void R_Shadow_Init(void)
738 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
739 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
740 Cvar_RegisterVariable(&r_shadow_usebihculling);
741 Cvar_RegisterVariable(&r_shadow_usenormalmap);
742 Cvar_RegisterVariable(&r_shadow_debuglight);
743 Cvar_RegisterVariable(&r_shadow_deferred);
744 Cvar_RegisterVariable(&r_shadow_gloss);
745 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
746 Cvar_RegisterVariable(&r_shadow_glossintensity);
747 Cvar_RegisterVariable(&r_shadow_glossexponent);
748 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
749 Cvar_RegisterVariable(&r_shadow_glossexact);
750 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
751 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
752 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
753 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
754 Cvar_RegisterVariable(&r_shadow_projectdistance);
755 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
756 Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
757 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
758 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
759 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
760 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
761 Cvar_RegisterVariable(&r_shadow_realtime_world);
762 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
763 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
764 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
765 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
766 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
767 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
768 Cvar_RegisterVariable(&r_shadow_scissor);
769 Cvar_RegisterVariable(&r_shadow_shadowmapping);
770 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
771 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
772 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
773 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
774 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
775 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
776 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
777 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturesize);
778 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
779 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
780 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
781 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
782 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
783 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
784 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
785 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
786 Cvar_RegisterVariable(&r_shadow_polygonfactor);
787 Cvar_RegisterVariable(&r_shadow_polygonoffset);
788 Cvar_RegisterVariable(&r_shadow_texture3d);
789 Cvar_RegisterVariable(&r_shadow_bouncegrid);
790 Cvar_RegisterVariable(&r_shadow_bouncegrid_blur);
791 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
792 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_culllightpaths);
793 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_directionalshading);
794 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_dlightparticlemultiplier);
795 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_hitmodels);
796 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_energyperphoton);
797 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_lightradiusscale);
798 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxbounce);
799 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxphotons);
800 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_spacing);
801 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_stablerandom);
802 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_updateinterval);
803 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_x);
804 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_y);
805 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_z);
806 Cvar_RegisterVariable(&r_shadow_bouncegrid_floatcolors);
807 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
808 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
809 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize);
810 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
811 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
812 Cvar_RegisterVariable(&r_shadow_bouncegrid_sortlightpaths);
813 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
814 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_spacing);
815 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
816 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
817 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
818 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxphotons);
819 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_energyperphoton);
820 Cvar_RegisterVariable(&r_coronas);
821 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
822 Cvar_RegisterVariable(&r_coronas_occlusionquery);
823 Cvar_RegisterVariable(&gl_flashblend);
824 Cvar_RegisterVariable(&gl_ext_separatestencil);
825 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
826 R_Shadow_EditLights_Init();
827 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
828 r_shadow_scenemaxlights = 0;
829 r_shadow_scenenumlights = 0;
830 r_shadow_scenelightlist = NULL;
831 maxshadowtriangles = 0;
832 shadowelements = NULL;
833 maxshadowvertices = 0;
834 shadowvertex3f = NULL;
842 shadowmarklist = NULL;
847 shadowsideslist = NULL;
848 r_shadow_buffer_numleafpvsbytes = 0;
849 r_shadow_buffer_visitingleafpvs = NULL;
850 r_shadow_buffer_leafpvs = NULL;
851 r_shadow_buffer_leaflist = NULL;
852 r_shadow_buffer_numsurfacepvsbytes = 0;
853 r_shadow_buffer_surfacepvs = NULL;
854 r_shadow_buffer_surfacelist = NULL;
855 r_shadow_buffer_surfacesides = NULL;
856 r_shadow_buffer_shadowtrispvs = NULL;
857 r_shadow_buffer_lighttrispvs = NULL;
858 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
861 matrix4x4_t matrix_attenuationxyz =
864 {0.5, 0.0, 0.0, 0.5},
865 {0.0, 0.5, 0.0, 0.5},
866 {0.0, 0.0, 0.5, 0.5},
871 matrix4x4_t matrix_attenuationz =
874 {0.0, 0.0, 0.5, 0.5},
875 {0.0, 0.0, 0.0, 0.5},
876 {0.0, 0.0, 0.0, 0.5},
881 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
883 numvertices = ((numvertices + 255) & ~255) * vertscale;
884 numtriangles = ((numtriangles + 255) & ~255) * triscale;
885 // make sure shadowelements is big enough for this volume
886 if (maxshadowtriangles < numtriangles)
888 maxshadowtriangles = numtriangles;
890 Mem_Free(shadowelements);
891 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
893 // make sure shadowvertex3f is big enough for this volume
894 if (maxshadowvertices < numvertices)
896 maxshadowvertices = numvertices;
898 Mem_Free(shadowvertex3f);
899 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
903 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
905 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
906 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
907 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
908 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
909 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
911 if (r_shadow_buffer_visitingleafpvs)
912 Mem_Free(r_shadow_buffer_visitingleafpvs);
913 if (r_shadow_buffer_leafpvs)
914 Mem_Free(r_shadow_buffer_leafpvs);
915 if (r_shadow_buffer_leaflist)
916 Mem_Free(r_shadow_buffer_leaflist);
917 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
918 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
919 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
920 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
922 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
924 if (r_shadow_buffer_surfacepvs)
925 Mem_Free(r_shadow_buffer_surfacepvs);
926 if (r_shadow_buffer_surfacelist)
927 Mem_Free(r_shadow_buffer_surfacelist);
928 if (r_shadow_buffer_surfacesides)
929 Mem_Free(r_shadow_buffer_surfacesides);
930 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
931 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
932 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
933 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
935 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
937 if (r_shadow_buffer_shadowtrispvs)
938 Mem_Free(r_shadow_buffer_shadowtrispvs);
939 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
940 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
942 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
944 if (r_shadow_buffer_lighttrispvs)
945 Mem_Free(r_shadow_buffer_lighttrispvs);
946 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
947 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
951 void R_Shadow_PrepareShadowMark(int numtris)
953 // make sure shadowmark is big enough for this volume
954 if (maxshadowmark < numtris)
956 maxshadowmark = numtris;
958 Mem_Free(shadowmark);
960 Mem_Free(shadowmarklist);
961 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
962 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
966 // if shadowmarkcount wrapped we clear the array and adjust accordingly
967 if (shadowmarkcount == 0)
970 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
975 void R_Shadow_PrepareShadowSides(int numtris)
977 if (maxshadowsides < numtris)
979 maxshadowsides = numtris;
981 Mem_Free(shadowsides);
983 Mem_Free(shadowsideslist);
984 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
985 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
990 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)
993 int outtriangles = 0, outvertices = 0;
996 float ratio, direction[3], projectvector[3];
998 if (projectdirection)
999 VectorScale(projectdirection, projectdistance, projectvector);
1001 VectorClear(projectvector);
1003 // create the vertices
1004 if (projectdirection)
1006 for (i = 0;i < numshadowmarktris;i++)
1008 element = inelement3i + shadowmarktris[i] * 3;
1009 for (j = 0;j < 3;j++)
1011 if (vertexupdate[element[j]] != vertexupdatenum)
1013 vertexupdate[element[j]] = vertexupdatenum;
1014 vertexremap[element[j]] = outvertices;
1015 vertex = invertex3f + element[j] * 3;
1016 // project one copy of the vertex according to projectvector
1017 VectorCopy(vertex, outvertex3f);
1018 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1027 for (i = 0;i < numshadowmarktris;i++)
1029 element = inelement3i + shadowmarktris[i] * 3;
1030 for (j = 0;j < 3;j++)
1032 if (vertexupdate[element[j]] != vertexupdatenum)
1034 vertexupdate[element[j]] = vertexupdatenum;
1035 vertexremap[element[j]] = outvertices;
1036 vertex = invertex3f + element[j] * 3;
1037 // project one copy of the vertex to the sphere radius of the light
1038 // (FIXME: would projecting it to the light box be better?)
1039 VectorSubtract(vertex, projectorigin, direction);
1040 ratio = projectdistance / VectorLength(direction);
1041 VectorCopy(vertex, outvertex3f);
1042 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1050 if (r_shadow_frontsidecasting.integer)
1052 for (i = 0;i < numshadowmarktris;i++)
1054 int remappedelement[3];
1056 const int *neighbortriangle;
1058 markindex = shadowmarktris[i] * 3;
1059 element = inelement3i + markindex;
1060 neighbortriangle = inneighbor3i + markindex;
1061 // output the front and back triangles
1062 outelement3i[0] = vertexremap[element[0]];
1063 outelement3i[1] = vertexremap[element[1]];
1064 outelement3i[2] = vertexremap[element[2]];
1065 outelement3i[3] = vertexremap[element[2]] + 1;
1066 outelement3i[4] = vertexremap[element[1]] + 1;
1067 outelement3i[5] = vertexremap[element[0]] + 1;
1071 // output the sides (facing outward from this triangle)
1072 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1074 remappedelement[0] = vertexremap[element[0]];
1075 remappedelement[1] = vertexremap[element[1]];
1076 outelement3i[0] = remappedelement[1];
1077 outelement3i[1] = remappedelement[0];
1078 outelement3i[2] = remappedelement[0] + 1;
1079 outelement3i[3] = remappedelement[1];
1080 outelement3i[4] = remappedelement[0] + 1;
1081 outelement3i[5] = remappedelement[1] + 1;
1086 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1088 remappedelement[1] = vertexremap[element[1]];
1089 remappedelement[2] = vertexremap[element[2]];
1090 outelement3i[0] = remappedelement[2];
1091 outelement3i[1] = remappedelement[1];
1092 outelement3i[2] = remappedelement[1] + 1;
1093 outelement3i[3] = remappedelement[2];
1094 outelement3i[4] = remappedelement[1] + 1;
1095 outelement3i[5] = remappedelement[2] + 1;
1100 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1102 remappedelement[0] = vertexremap[element[0]];
1103 remappedelement[2] = vertexremap[element[2]];
1104 outelement3i[0] = remappedelement[0];
1105 outelement3i[1] = remappedelement[2];
1106 outelement3i[2] = remappedelement[2] + 1;
1107 outelement3i[3] = remappedelement[0];
1108 outelement3i[4] = remappedelement[2] + 1;
1109 outelement3i[5] = remappedelement[0] + 1;
1118 for (i = 0;i < numshadowmarktris;i++)
1120 int remappedelement[3];
1122 const int *neighbortriangle;
1124 markindex = shadowmarktris[i] * 3;
1125 element = inelement3i + markindex;
1126 neighbortriangle = inneighbor3i + markindex;
1127 // output the front and back triangles
1128 outelement3i[0] = vertexremap[element[2]];
1129 outelement3i[1] = vertexremap[element[1]];
1130 outelement3i[2] = vertexremap[element[0]];
1131 outelement3i[3] = vertexremap[element[0]] + 1;
1132 outelement3i[4] = vertexremap[element[1]] + 1;
1133 outelement3i[5] = vertexremap[element[2]] + 1;
1137 // output the sides (facing outward from this triangle)
1138 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1140 remappedelement[0] = vertexremap[element[0]];
1141 remappedelement[1] = vertexremap[element[1]];
1142 outelement3i[0] = remappedelement[0];
1143 outelement3i[1] = remappedelement[1];
1144 outelement3i[2] = remappedelement[1] + 1;
1145 outelement3i[3] = remappedelement[0];
1146 outelement3i[4] = remappedelement[1] + 1;
1147 outelement3i[5] = remappedelement[0] + 1;
1152 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1154 remappedelement[1] = vertexremap[element[1]];
1155 remappedelement[2] = vertexremap[element[2]];
1156 outelement3i[0] = remappedelement[1];
1157 outelement3i[1] = remappedelement[2];
1158 outelement3i[2] = remappedelement[2] + 1;
1159 outelement3i[3] = remappedelement[1];
1160 outelement3i[4] = remappedelement[2] + 1;
1161 outelement3i[5] = remappedelement[1] + 1;
1166 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1168 remappedelement[0] = vertexremap[element[0]];
1169 remappedelement[2] = vertexremap[element[2]];
1170 outelement3i[0] = remappedelement[2];
1171 outelement3i[1] = remappedelement[0];
1172 outelement3i[2] = remappedelement[0] + 1;
1173 outelement3i[3] = remappedelement[2];
1174 outelement3i[4] = remappedelement[0] + 1;
1175 outelement3i[5] = remappedelement[2] + 1;
1183 *outnumvertices = outvertices;
1184 return outtriangles;
1187 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)
1190 int outtriangles = 0, outvertices = 0;
1192 const float *vertex;
1193 float ratio, direction[3], projectvector[3];
1196 if (projectdirection)
1197 VectorScale(projectdirection, projectdistance, projectvector);
1199 VectorClear(projectvector);
1201 for (i = 0;i < numshadowmarktris;i++)
1203 int remappedelement[3];
1205 const int *neighbortriangle;
1207 markindex = shadowmarktris[i] * 3;
1208 neighbortriangle = inneighbor3i + markindex;
1209 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1210 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1211 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1212 if (side[0] + side[1] + side[2] == 0)
1216 element = inelement3i + markindex;
1218 // create the vertices
1219 for (j = 0;j < 3;j++)
1221 if (side[j] + side[j+1] == 0)
1224 if (vertexupdate[k] != vertexupdatenum)
1226 vertexupdate[k] = vertexupdatenum;
1227 vertexremap[k] = outvertices;
1228 vertex = invertex3f + k * 3;
1229 VectorCopy(vertex, outvertex3f);
1230 if (projectdirection)
1232 // project one copy of the vertex according to projectvector
1233 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1237 // project one copy of the vertex to the sphere radius of the light
1238 // (FIXME: would projecting it to the light box be better?)
1239 VectorSubtract(vertex, projectorigin, direction);
1240 ratio = projectdistance / VectorLength(direction);
1241 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1248 // output the sides (facing outward from this triangle)
1251 remappedelement[0] = vertexremap[element[0]];
1252 remappedelement[1] = vertexremap[element[1]];
1253 outelement3i[0] = remappedelement[1];
1254 outelement3i[1] = remappedelement[0];
1255 outelement3i[2] = remappedelement[0] + 1;
1256 outelement3i[3] = remappedelement[1];
1257 outelement3i[4] = remappedelement[0] + 1;
1258 outelement3i[5] = remappedelement[1] + 1;
1265 remappedelement[1] = vertexremap[element[1]];
1266 remappedelement[2] = vertexremap[element[2]];
1267 outelement3i[0] = remappedelement[2];
1268 outelement3i[1] = remappedelement[1];
1269 outelement3i[2] = remappedelement[1] + 1;
1270 outelement3i[3] = remappedelement[2];
1271 outelement3i[4] = remappedelement[1] + 1;
1272 outelement3i[5] = remappedelement[2] + 1;
1279 remappedelement[0] = vertexremap[element[0]];
1280 remappedelement[2] = vertexremap[element[2]];
1281 outelement3i[0] = remappedelement[0];
1282 outelement3i[1] = remappedelement[2];
1283 outelement3i[2] = remappedelement[2] + 1;
1284 outelement3i[3] = remappedelement[0];
1285 outelement3i[4] = remappedelement[2] + 1;
1286 outelement3i[5] = remappedelement[0] + 1;
1293 *outnumvertices = outvertices;
1294 return outtriangles;
1297 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)
1303 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1305 tend = firsttriangle + numtris;
1306 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1308 // surface box entirely inside light box, no box cull
1309 if (projectdirection)
1311 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1313 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1314 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1315 shadowmarklist[numshadowmark++] = t;
1320 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1321 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1322 shadowmarklist[numshadowmark++] = t;
1327 // surface box not entirely inside light box, cull each triangle
1328 if (projectdirection)
1330 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1332 v[0] = invertex3f + e[0] * 3;
1333 v[1] = invertex3f + e[1] * 3;
1334 v[2] = invertex3f + e[2] * 3;
1335 TriangleNormal(v[0], v[1], v[2], normal);
1336 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1337 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1338 shadowmarklist[numshadowmark++] = t;
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 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1349 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1350 shadowmarklist[numshadowmark++] = t;
1356 static qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1361 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1363 // check if the shadow volume intersects the near plane
1365 // a ray between the eye and light origin may intersect the caster,
1366 // indicating that the shadow may touch the eye location, however we must
1367 // test the near plane (a polygon), not merely the eye location, so it is
1368 // easiest to enlarge the caster bounding shape slightly for this.
1374 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)
1376 int i, tris, outverts;
1377 if (projectdistance < 0.1)
1379 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1382 if (!numverts || !nummarktris)
1384 // make sure shadowelements is big enough for this volume
1385 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1386 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1388 if (maxvertexupdate < numverts)
1390 maxvertexupdate = numverts;
1392 Mem_Free(vertexupdate);
1394 Mem_Free(vertexremap);
1395 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1396 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1397 vertexupdatenum = 0;
1400 if (vertexupdatenum == 0)
1402 vertexupdatenum = 1;
1403 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1404 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1407 for (i = 0;i < nummarktris;i++)
1408 shadowmark[marktris[i]] = shadowmarkcount;
1410 if (r_shadow_compilingrtlight)
1412 // if we're compiling an rtlight, capture the mesh
1413 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1414 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1415 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1416 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1418 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1420 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1421 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1422 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1426 // decide which type of shadow to generate and set stencil mode
1427 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1428 // generate the sides or a solid volume, depending on type
1429 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1430 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1432 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1433 r_refdef.stats[r_stat_lights_dynamicshadowtriangles] += tris;
1434 r_refdef.stats[r_stat_lights_shadowtriangles] += tris;
1435 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1437 // increment stencil if frontface is infront of depthbuffer
1438 GL_CullFace(r_refdef.view.cullface_front);
1439 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1440 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1441 // decrement stencil if backface is infront of depthbuffer
1442 GL_CullFace(r_refdef.view.cullface_back);
1443 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1445 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1447 // decrement stencil if backface is behind depthbuffer
1448 GL_CullFace(r_refdef.view.cullface_front);
1449 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1450 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1451 // increment stencil if frontface is behind depthbuffer
1452 GL_CullFace(r_refdef.view.cullface_back);
1453 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1455 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1456 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1460 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1462 // p1, p2, p3 are in the cubemap's local coordinate system
1463 // bias = border/(size - border)
1466 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1467 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1468 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1469 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1471 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1472 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1473 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1474 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1476 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1477 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1478 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1480 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1481 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1482 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1483 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1485 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1486 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1487 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1488 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1490 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1491 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1492 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1494 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1495 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1496 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1497 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1499 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1500 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1501 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1502 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1504 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1505 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1506 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1511 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1513 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1514 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1517 VectorSubtract(maxs, mins, radius);
1518 VectorScale(radius, 0.5f, radius);
1519 VectorAdd(mins, radius, center);
1520 Matrix4x4_Transform(worldtolight, center, lightcenter);
1521 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1522 VectorSubtract(lightcenter, lightradius, pmin);
1523 VectorAdd(lightcenter, lightradius, pmax);
1525 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1526 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1527 if(ap1 > bias*an1 && ap2 > bias*an2)
1529 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1530 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1531 if(an1 > bias*ap1 && an2 > bias*ap2)
1533 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1534 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1536 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1537 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1538 if(ap1 > bias*an1 && ap2 > bias*an2)
1540 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1541 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1542 if(an1 > bias*ap1 && an2 > bias*ap2)
1544 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1545 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1547 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1548 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1549 if(ap1 > bias*an1 && ap2 > bias*an2)
1551 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1552 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1553 if(an1 > bias*ap1 && an2 > bias*ap2)
1555 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1556 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1561 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1563 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1565 // p is in the cubemap's local coordinate system
1566 // bias = border/(size - border)
1567 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1568 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1569 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1571 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1572 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1573 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1574 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1575 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1576 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1580 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1584 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1585 float scale = (size - 2*border)/size, len;
1586 float bias = border / (float)(size - border), dp, dn, ap, an;
1587 // check if cone enclosing side would cross frustum plane
1588 scale = 2 / (scale*scale + 2);
1589 Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
1590 for (i = 0;i < 5;i++)
1592 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
1594 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1595 len = scale*VectorLength2(n);
1596 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1597 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1598 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1600 if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1602 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1603 len = scale*VectorLength2(n);
1604 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1605 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1606 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1608 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1609 // check if frustum corners/origin cross plane sides
1611 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1612 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1613 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1614 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1615 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1616 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1617 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1618 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1619 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1620 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1621 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1622 for (i = 0;i < 4;i++)
1624 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1625 VectorSubtract(n, p, n);
1626 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1627 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1628 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1629 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1630 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1631 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1632 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1633 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1634 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1637 // finite version, assumes corners are a finite distance from origin dependent on far plane
1638 for (i = 0;i < 5;i++)
1640 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1641 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1642 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1643 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1644 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1645 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1646 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1647 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1648 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1649 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1652 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1655 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)
1663 int mask, surfacemask = 0;
1664 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1666 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1667 tend = firsttriangle + numtris;
1668 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1670 // surface box entirely inside light box, no box cull
1671 if (projectdirection)
1673 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1675 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1676 TriangleNormal(v[0], v[1], v[2], normal);
1677 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1679 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1680 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1681 surfacemask |= mask;
1684 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;
1685 shadowsides[numshadowsides] = mask;
1686 shadowsideslist[numshadowsides++] = t;
1693 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1695 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1696 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1698 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1699 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1700 surfacemask |= mask;
1703 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;
1704 shadowsides[numshadowsides] = mask;
1705 shadowsideslist[numshadowsides++] = t;
1713 // surface box not entirely inside light box, cull each triangle
1714 if (projectdirection)
1716 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1718 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1719 TriangleNormal(v[0], v[1], v[2], normal);
1720 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1721 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1723 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1724 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1725 surfacemask |= mask;
1728 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;
1729 shadowsides[numshadowsides] = mask;
1730 shadowsideslist[numshadowsides++] = t;
1737 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1739 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1740 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1741 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1743 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1744 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1745 surfacemask |= mask;
1748 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;
1749 shadowsides[numshadowsides] = mask;
1750 shadowsideslist[numshadowsides++] = t;
1759 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)
1761 int i, j, outtriangles = 0;
1762 int *outelement3i[6];
1763 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1765 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1766 // make sure shadowelements is big enough for this mesh
1767 if (maxshadowtriangles < outtriangles)
1768 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1770 // compute the offset and size of the separate index lists for each cubemap side
1772 for (i = 0;i < 6;i++)
1774 outelement3i[i] = shadowelements + outtriangles * 3;
1775 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1776 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1777 outtriangles += sidetotals[i];
1780 // gather up the (sparse) triangles into separate index lists for each cubemap side
1781 for (i = 0;i < numsidetris;i++)
1783 const int *element = elements + sidetris[i] * 3;
1784 for (j = 0;j < 6;j++)
1786 if (sides[i] & (1 << j))
1788 outelement3i[j][0] = element[0];
1789 outelement3i[j][1] = element[1];
1790 outelement3i[j][2] = element[2];
1791 outelement3i[j] += 3;
1796 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1799 static void R_Shadow_MakeTextures_MakeCorona(void)
1803 unsigned char pixels[32][32][4];
1804 for (y = 0;y < 32;y++)
1806 dy = (y - 15.5f) * (1.0f / 16.0f);
1807 for (x = 0;x < 32;x++)
1809 dx = (x - 15.5f) * (1.0f / 16.0f);
1810 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1811 a = bound(0, a, 255);
1812 pixels[y][x][0] = a;
1813 pixels[y][x][1] = a;
1814 pixels[y][x][2] = a;
1815 pixels[y][x][3] = 255;
1818 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, false);
1821 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1823 float dist = sqrt(x*x+y*y+z*z);
1824 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1825 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1826 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1829 static void R_Shadow_MakeTextures(void)
1832 float intensity, dist;
1834 R_Shadow_FreeShadowMaps();
1835 R_FreeTexturePool(&r_shadow_texturepool);
1836 r_shadow_texturepool = R_AllocTexturePool();
1837 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1838 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1839 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1840 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1841 for (x = 0;x <= ATTENTABLESIZE;x++)
1843 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1844 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1845 r_shadow_attentable[x] = bound(0, intensity, 1);
1847 // 1D gradient texture
1848 for (x = 0;x < ATTEN1DSIZE;x++)
1849 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1850 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1851 // 2D circle texture
1852 for (y = 0;y < ATTEN2DSIZE;y++)
1853 for (x = 0;x < ATTEN2DSIZE;x++)
1854 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);
1855 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1856 // 3D sphere texture
1857 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1859 for (z = 0;z < ATTEN3DSIZE;z++)
1860 for (y = 0;y < ATTEN3DSIZE;y++)
1861 for (x = 0;x < ATTEN3DSIZE;x++)
1862 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));
1863 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);
1866 r_shadow_attenuation3dtexture = NULL;
1869 R_Shadow_MakeTextures_MakeCorona();
1871 // Editor light sprites
1872 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1889 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1890 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1907 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1908 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1925 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1926 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1943 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1944 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1961 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1962 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1979 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1982 void R_Shadow_ValidateCvars(void)
1984 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1985 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1986 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1987 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1988 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1989 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1992 void R_Shadow_RenderMode_Begin(void)
1998 R_Shadow_ValidateCvars();
2000 if (!r_shadow_attenuation2dtexture
2001 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
2002 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
2003 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
2004 R_Shadow_MakeTextures();
2007 R_Mesh_ResetTextureState();
2008 GL_BlendFunc(GL_ONE, GL_ZERO);
2009 GL_DepthRange(0, 1);
2010 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
2012 GL_DepthMask(false);
2013 GL_Color(0, 0, 0, 1);
2014 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2016 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2018 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
2020 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
2021 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
2023 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
2025 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
2026 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
2030 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
2031 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
2034 switch(vid.renderpath)
2036 case RENDERPATH_GL20:
2037 case RENDERPATH_D3D9:
2038 case RENDERPATH_D3D10:
2039 case RENDERPATH_D3D11:
2040 case RENDERPATH_SOFT:
2041 case RENDERPATH_GLES2:
2042 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
2044 case RENDERPATH_GL11:
2045 case RENDERPATH_GL13:
2046 case RENDERPATH_GLES1:
2047 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
2048 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
2049 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
2050 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
2051 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
2052 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
2054 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
2060 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
2061 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
2062 r_shadow_drawbuffer = drawbuffer;
2063 r_shadow_readbuffer = readbuffer;
2065 r_shadow_cullface_front = r_refdef.view.cullface_front;
2066 r_shadow_cullface_back = r_refdef.view.cullface_back;
2069 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
2071 rsurface.rtlight = rtlight;
2074 void R_Shadow_RenderMode_Reset(void)
2076 R_Mesh_ResetTextureState();
2077 R_Mesh_SetRenderTargets(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture, NULL, NULL, NULL);
2078 R_SetViewport(&r_refdef.view.viewport);
2079 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
2080 GL_DepthRange(0, 1);
2082 GL_DepthMask(false);
2083 GL_DepthFunc(GL_LEQUAL);
2084 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2085 r_refdef.view.cullface_front = r_shadow_cullface_front;
2086 r_refdef.view.cullface_back = r_shadow_cullface_back;
2087 GL_CullFace(r_refdef.view.cullface_back);
2088 GL_Color(1, 1, 1, 1);
2089 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2090 GL_BlendFunc(GL_ONE, GL_ZERO);
2091 R_SetupShader_Generic_NoTexture(false, false);
2092 r_shadow_usingshadowmap2d = false;
2093 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2096 void R_Shadow_ClearStencil(void)
2098 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2099 r_refdef.stats[r_stat_lights_clears]++;
2102 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2104 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2105 if (r_shadow_rendermode == mode)
2107 R_Shadow_RenderMode_Reset();
2108 GL_DepthFunc(GL_LESS);
2109 GL_ColorMask(0, 0, 0, 0);
2110 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2111 GL_CullFace(GL_NONE);
2112 R_SetupShader_DepthOrShadow(false, false, false); // FIXME test if we have a skeletal model?
2113 r_shadow_rendermode = mode;
2118 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2119 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2120 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2122 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2123 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2124 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2129 static void R_Shadow_MakeVSDCT(void)
2131 // maps to a 2x3 texture rectangle with normalized coordinates
2136 // stores abs(dir.xy), offset.xy/2.5
2137 unsigned char data[4*6] =
2139 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2140 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2141 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2142 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2143 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2144 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2146 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2149 static void R_Shadow_MakeShadowMap(int texturesize)
2151 switch (r_shadow_shadowmode)
2153 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2154 if (r_shadow_shadowmap2ddepthtexture) return;
2155 if (r_fb.usedepthtextures)
2157 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);
2158 r_shadow_shadowmap2ddepthbuffer = NULL;
2159 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2163 r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", texturesize, texturesize, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2164 r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
2165 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2173 void R_Shadow_ClearShadowMapTexture(void)
2175 r_viewport_t viewport;
2176 float clearcolor[4];
2178 // if they don't exist, create our textures now
2179 if (!r_shadow_shadowmap2ddepthtexture)
2180 R_Shadow_MakeShadowMap(r_shadow_shadowmaptexturesize);
2181 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2182 R_Shadow_MakeVSDCT();
2184 // we're setting up to render shadowmaps, so change rendermode
2185 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2187 R_Mesh_ResetTextureState();
2188 R_Shadow_RenderMode_Reset();
2189 if (r_shadow_shadowmap2ddepthbuffer)
2190 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2192 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2193 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2194 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2198 // we have to set a viewport to clear anything in some renderpaths (D3D)
2199 R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize, 0, 0, 1.0, 1.0, 0.001f, 1.0f, NULL);
2200 R_SetViewport(&viewport);
2201 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2202 if (r_shadow_shadowmap2ddepthbuffer)
2203 GL_ColorMask(1, 1, 1, 1);
2205 GL_ColorMask(0, 0, 0, 0);
2206 switch (vid.renderpath)
2208 case RENDERPATH_GL11:
2209 case RENDERPATH_GL13:
2210 case RENDERPATH_GL20:
2211 case RENDERPATH_SOFT:
2212 case RENDERPATH_GLES1:
2213 case RENDERPATH_GLES2:
2214 GL_CullFace(r_refdef.view.cullface_back);
2216 case RENDERPATH_D3D9:
2217 case RENDERPATH_D3D10:
2218 case RENDERPATH_D3D11:
2219 // we invert the cull mode because we flip the projection matrix
2220 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2221 GL_CullFace(r_refdef.view.cullface_front);
2224 Vector4Set(clearcolor, 1, 1, 1, 1);
2225 if (r_shadow_shadowmap2ddepthbuffer)
2226 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2228 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2231 static void R_Shadow_SetShadowmapParametersForLight(qboolean noselfshadowpass)
2233 int size = rsurface.rtlight->shadowmapatlassidesize;
2234 float nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2235 float farclip = 1.0f;
2236 float bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2237 r_shadow_lightshadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
2238 r_shadow_lightshadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
2239 r_shadow_lightshadowmap_texturescale[2] = rsurface.rtlight->shadowmapatlasposition[0] + (noselfshadowpass ? size * 2 : 0);
2240 r_shadow_lightshadowmap_texturescale[3] = rsurface.rtlight->shadowmapatlasposition[1];
2241 r_shadow_lightshadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2242 r_shadow_lightshadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2243 r_shadow_lightshadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2244 r_shadow_lightshadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2245 if (r_shadow_shadowmap2ddepthbuffer)
2247 // completely different meaning than in depthtexture approach
2248 r_shadow_lightshadowmap_parameters[1] = 0;
2249 r_shadow_lightshadowmap_parameters[3] = -bias;
2253 static void R_Shadow_RenderMode_ShadowMap(int side, int size, int x, int y)
2255 float nearclip, farclip, bias;
2256 r_viewport_t viewport;
2258 float clearcolor[4];
2260 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_SHADOWMAP2D)
2262 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2264 R_Mesh_ResetTextureState();
2265 R_Shadow_RenderMode_Reset();
2266 if (r_shadow_shadowmap2ddepthbuffer)
2267 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2269 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2270 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2271 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2276 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2278 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2280 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
2281 R_SetViewport(&viewport);
2282 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2283 flipped = (side & 1) ^ (side >> 2);
2284 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2285 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2287 Vector4Set(clearcolor, 1,1,1,1);
2288 if (r_shadow_shadowmap2ddepthbuffer)
2289 GL_ColorMask(1,1,1,1);
2291 GL_ColorMask(0,0,0,0);
2292 switch(vid.renderpath)
2294 case RENDERPATH_GL11:
2295 case RENDERPATH_GL13:
2296 case RENDERPATH_GL20:
2297 case RENDERPATH_SOFT:
2298 case RENDERPATH_GLES1:
2299 case RENDERPATH_GLES2:
2300 GL_CullFace(r_refdef.view.cullface_back);
2302 case RENDERPATH_D3D9:
2303 case RENDERPATH_D3D10:
2304 case RENDERPATH_D3D11:
2305 // we invert the cull mode because we flip the projection matrix
2306 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2307 GL_CullFace(r_refdef.view.cullface_front);
2311 // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
2312 r_shadow_shadowmapside = side;
2315 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass)
2317 R_Mesh_ResetTextureState();
2320 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2321 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2322 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2323 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2326 R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
2327 R_Shadow_RenderMode_Reset();
2328 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2330 GL_DepthFunc(GL_EQUAL);
2331 // do global setup needed for the chosen lighting mode
2332 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2333 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2334 r_shadow_usingshadowmap2d = shadowmapping;
2335 r_shadow_rendermode = r_shadow_lightingrendermode;
2336 // only draw light where this geometry was already rendered AND the
2337 // stencil is 128 (values other than this mean shadow)
2339 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2341 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2344 static const unsigned short bboxelements[36] =
2354 static const float bboxpoints[8][3] =
2366 void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping)
2369 float vertex3f[8*3];
2370 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2371 // do global setup needed for the chosen lighting mode
2372 R_Shadow_RenderMode_Reset();
2373 r_shadow_rendermode = r_shadow_lightingrendermode;
2374 R_EntityMatrix(&identitymatrix);
2375 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2376 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2377 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
2378 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2380 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
2382 r_shadow_usingshadowmap2d = shadowmapping;
2384 // render the lighting
2385 R_SetupShader_DeferredLight(rsurface.rtlight);
2386 for (i = 0;i < 8;i++)
2387 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2388 GL_ColorMask(1,1,1,1);
2389 GL_DepthMask(false);
2390 GL_DepthRange(0, 1);
2391 GL_PolygonOffset(0, 0);
2393 GL_DepthFunc(GL_GREATER);
2394 GL_CullFace(r_refdef.view.cullface_back);
2395 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
2396 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2399 #define MAXBOUNCEGRIDSPLATSIZE 7
2400 #define MAXBOUNCEGRIDSPLATSIZE1 (MAXBOUNCEGRIDSPLATSIZE+1)
2402 // these are temporary data per-frame, sorted and performed in a more
2403 // cache-friendly order than the original photons
2404 typedef struct r_shadow_bouncegrid_splatpath_s
2410 vec_t splatintensity;
2411 int remainingsplats;
2413 r_shadow_bouncegrid_splatpath_t;
2415 static void R_Shadow_BounceGrid_AddSplatPath(vec3_t originalstart, vec3_t originalend, vec3_t color)
2425 r_shadow_bouncegrid_splatpath_t *path;
2427 // cull paths that fail R_CullBox in dynamic mode
2428 if (!r_shadow_bouncegrid_state.settings.staticmode
2429 && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
2431 vec3_t cullmins, cullmaxs;
2432 cullmins[0] = min(originalstart[0], originalend[0]) - r_shadow_bouncegrid_state.settings.spacing[0];
2433 cullmins[1] = min(originalstart[1], originalend[1]) - r_shadow_bouncegrid_state.settings.spacing[1];
2434 cullmins[2] = min(originalstart[2], originalend[2]) - r_shadow_bouncegrid_state.settings.spacing[2];
2435 cullmaxs[0] = max(originalstart[0], originalend[0]) + r_shadow_bouncegrid_state.settings.spacing[0];
2436 cullmaxs[1] = max(originalstart[1], originalend[1]) + r_shadow_bouncegrid_state.settings.spacing[1];
2437 cullmaxs[2] = max(originalstart[2], originalend[2]) + r_shadow_bouncegrid_state.settings.spacing[2];
2438 if (R_CullBox(cullmins, cullmaxs))
2442 // if the light path is going upward, reverse it - we always draw down.
2443 if (originalend[2] < originalstart[2])
2445 VectorCopy(originalend, start);
2446 VectorCopy(originalstart, end);
2450 VectorCopy(originalstart, start);
2451 VectorCopy(originalend, end);
2454 // transform to texture pixels
2455 start[0] = (start[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2456 start[1] = (start[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2457 start[2] = (start[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2458 end[0] = (end[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2459 end[1] = (end[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2460 end[2] = (end[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2462 // check if we need to grow the splatpaths array
2463 if (r_shadow_bouncegrid_state.maxsplatpaths <= r_shadow_bouncegrid_state.numsplatpaths)
2465 // double the limit, this will persist from frame to frame so we don't
2466 // make the same mistake each time
2467 r_shadow_bouncegrid_splatpath_t *newpaths;
2468 r_shadow_bouncegrid_state.maxsplatpaths *= 2;
2469 newpaths = (r_shadow_bouncegrid_splatpath_t *)R_FrameData_Alloc(sizeof(r_shadow_bouncegrid_splatpath_t) * r_shadow_bouncegrid_state.maxsplatpaths);
2470 if (r_shadow_bouncegrid_state.splatpaths)
2471 memcpy(newpaths, r_shadow_bouncegrid_state.splatpaths, r_shadow_bouncegrid_state.numsplatpaths * sizeof(r_shadow_bouncegrid_splatpath_t));
2472 r_shadow_bouncegrid_state.splatpaths = newpaths;
2475 // divide a series of splats along the length using the maximum axis
2476 VectorSubtract(end, start, diff);
2477 // pick the best axis to trace along
2479 if (diff[1]*diff[1] > diff[bestaxis]*diff[bestaxis])
2481 if (diff[2]*diff[2] > diff[bestaxis]*diff[bestaxis])
2483 len = fabs(diff[bestaxis]);
2485 numsplats = (int)(floor(len + 0.5f));
2487 numsplats = bound(0, numsplats, 1024);
2489 VectorSubtract(originalstart, originalend, originaldir);
2490 VectorNormalize(originaldir);
2492 path = r_shadow_bouncegrid_state.splatpaths + r_shadow_bouncegrid_state.numsplatpaths++;
2493 VectorCopy(start, path->point);
2494 VectorScale(diff, ilen, path->step);
2495 VectorCopy(color, path->splatcolor);
2496 VectorCopy(originaldir, path->splatdir);
2497 path->splatintensity = VectorLength(color);
2498 path->remainingsplats = numsplats;
2501 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
2503 qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
2510 // see if there are really any lights to render...
2511 if (enable && r_shadow_bouncegrid_static.integer)
2514 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2515 for (lightindex = 0;lightindex < range;lightindex++)
2517 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2518 if (!light || !(light->flags & flag))
2520 rtlight = &light->rtlight;
2521 // when static, we skip styled lights because they tend to change...
2522 if (rtlight->style > 0)
2524 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
2525 if (!VectorLength2(lightcolor))
2535 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
2537 qboolean s = r_shadow_bouncegrid_static.integer != 0;
2538 float spacing = s ? r_shadow_bouncegrid_static_spacing.value : r_shadow_bouncegrid_dynamic_spacing.value;
2540 // prevent any garbage in alignment padded areas as we'll be using memcmp
2541 memset(settings, 0, sizeof(*settings));
2543 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
2544 settings->staticmode = s;
2545 settings->blur = r_shadow_bouncegrid_blur.integer != 0;
2546 settings->floatcolors = bound(0, r_shadow_bouncegrid_floatcolors.integer, 2);
2547 settings->lightpathsize = bound(1, r_shadow_bouncegrid_lightpathsize.integer, MAXBOUNCEGRIDSPLATSIZE);
2548 settings->bounceanglediffuse = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
2549 settings->directionalshading = (s ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_dynamic_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
2550 settings->dlightparticlemultiplier = s ? 0 : r_shadow_bouncegrid_dynamic_dlightparticlemultiplier.value;
2551 settings->hitmodels = s ? false : r_shadow_bouncegrid_dynamic_hitmodels.integer != 0;
2552 settings->includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
2553 settings->lightradiusscale = (s ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_dynamic_lightradiusscale.value);
2554 settings->maxbounce = (s ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_dynamic_maxbounce.integer);
2555 settings->particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
2556 settings->particleintensity = r_shadow_bouncegrid_particleintensity.value * 16384.0f * (settings->directionalshading ? 4.0f : 1.0f) / (spacing * spacing);
2557 settings->maxphotons = s ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_dynamic_maxphotons.integer;
2558 settings->energyperphoton = s ? r_shadow_bouncegrid_static_energyperphoton.integer : r_shadow_bouncegrid_dynamic_energyperphoton.integer;
2559 settings->spacing[0] = spacing;
2560 settings->spacing[1] = spacing;
2561 settings->spacing[2] = spacing;
2562 settings->stablerandom = s ? 1 : r_shadow_bouncegrid_dynamic_stablerandom.integer;
2564 // bound the values for sanity
2565 settings->maxphotons = bound(1, settings->maxphotons, 25000000);
2566 settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
2567 settings->maxbounce = bound(0, settings->maxbounce, 16);
2568 settings->spacing[0] = bound(1, settings->spacing[0], 512);
2569 settings->spacing[1] = bound(1, settings->spacing[1], 512);
2570 settings->spacing[2] = bound(1, settings->spacing[2], 512);
2573 static void R_Shadow_BounceGrid_UpdateSpacing(void)
2584 r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
2586 // get the spacing values
2587 spacing[0] = settings->spacing[0];
2588 spacing[1] = settings->spacing[1];
2589 spacing[2] = settings->spacing[2];
2590 ispacing[0] = 1.0f / spacing[0];
2591 ispacing[1] = 1.0f / spacing[1];
2592 ispacing[2] = 1.0f / spacing[2];
2594 // calculate texture size enclosing entire world bounds at the spacing
2595 if (r_refdef.scene.worldmodel)
2597 VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
2598 VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
2602 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
2603 VectorSet(maxs, 1048576.0f, 1048576.0f, 1048576.0f);
2605 VectorSubtract(maxs, mins, size);
2606 // now we can calculate the resolution we want
2607 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2608 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2609 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2610 // figure out the exact texture size (honoring power of 2 if required)
2611 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2612 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2613 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2614 if (vid.support.arb_texture_non_power_of_two)
2616 resolution[0] = c[0];
2617 resolution[1] = c[1];
2618 resolution[2] = c[2];
2622 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2623 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2624 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2626 size[0] = spacing[0] * resolution[0];
2627 size[1] = spacing[1] * resolution[1];
2628 size[2] = spacing[2] * resolution[2];
2630 // if dynamic we may or may not want to use the world bounds
2631 // if the dynamic size is smaller than the world bounds, use it instead
2632 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]))
2634 // we know the resolution we want
2635 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
2636 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
2637 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
2638 // now we can calculate the texture size (power of 2 if required)
2639 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2640 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2641 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2642 if (vid.support.arb_texture_non_power_of_two)
2644 resolution[0] = c[0];
2645 resolution[1] = c[1];
2646 resolution[2] = c[2];
2650 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2651 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2652 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2654 size[0] = spacing[0] * resolution[0];
2655 size[1] = spacing[1] * resolution[1];
2656 size[2] = spacing[2] * resolution[2];
2657 // center the rendering on the view
2658 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2659 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2660 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2663 // recalculate the maxs in case the resolution was not satisfactory
2664 VectorAdd(mins, size, maxs);
2666 // check if this changed the texture size
2667 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);
2668 r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
2669 VectorCopy(mins, r_shadow_bouncegrid_state.mins);
2670 VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
2671 VectorCopy(size, r_shadow_bouncegrid_state.size);
2672 VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
2673 VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
2674 VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
2676 // reallocate pixels for this update if needed...
2677 r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
2678 r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
2679 r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
2680 numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
2681 if (r_shadow_bouncegrid_state.numpixels != numpixels)
2683 if (r_shadow_bouncegrid_state.texture)
2685 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2686 r_shadow_bouncegrid_state.texture = NULL;
2688 r_shadow_bouncegrid_state.numpixels = numpixels;
2691 // update the bouncegrid matrix to put it in the world properly
2692 memset(m, 0, sizeof(m));
2693 m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
2694 m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
2695 m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
2696 m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
2697 m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
2698 m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
2700 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
2703 #define MAXBOUNCEGRIDPARTICLESPERLIGHT 1048576
2705 // enumerate world rtlights and sum the overall amount of light in the world,
2706 // from that we can calculate a scaling factor to fairly distribute photons
2707 // to all the lights
2709 // this modifies rtlight->photoncolor and rtlight->photons
2710 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)
2712 float normalphotonscaling;
2713 float maxphotonscaling;
2714 float photoncount = 0.0f;
2715 float lightintensity;
2721 unsigned int lightindex;
2724 for (lightindex = 0;lightindex < range2;lightindex++)
2726 if (lightindex < range)
2728 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2731 rtlight = &light->rtlight;
2732 VectorClear(rtlight->photoncolor);
2733 rtlight->photons = 0;
2734 if (!(light->flags & flag))
2736 if (settings->staticmode)
2738 // when static, we skip styled lights because they tend to change...
2739 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2745 rtlight = r_refdef.scene.lights[lightindex - range];
2746 VectorClear(rtlight->photoncolor);
2747 rtlight->photons = 0;
2749 // draw only visible lights (major speedup)
2750 radius = rtlight->radius * settings->lightradiusscale;
2751 cullmins[0] = rtlight->shadoworigin[0] - radius;
2752 cullmins[1] = rtlight->shadoworigin[1] - radius;
2753 cullmins[2] = rtlight->shadoworigin[2] - radius;
2754 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2755 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2756 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2757 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2758 if (!settings->staticmode)
2760 if (R_CullBox(cullmins, cullmaxs))
2762 if (r_refdef.scene.worldmodel
2763 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2764 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2766 if (w * VectorLength2(rtlight->color) == 0.0f)
2769 // a light that does not emit any light before style is applied, can be
2770 // skipped entirely (it may just be a corona)
2771 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2773 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2774 VectorScale(rtlight->color, w, rtlight->photoncolor);
2775 // skip lights that will emit no photons
2776 if (!VectorLength2(rtlight->photoncolor))
2778 // shoot particles from this light
2779 // use a calculation for the number of particles that will not
2780 // vary with lightstyle, otherwise we get randomized particle
2781 // distribution, the seeded random is only consistent for a
2782 // consistent number of particles on this light...
2783 s = rtlight->radius;
2784 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2785 if (lightindex >= range)
2786 lightintensity *= settings->dlightparticlemultiplier;
2787 rtlight->photons = bound(0.0f, lightintensity * s * s, MAXBOUNCEGRIDPARTICLESPERLIGHT);
2788 photoncount += rtlight->photons;
2789 // if the lightstyle happens to be off right now, we can skip actually
2790 // firing the photons, but we did have to count them in the total.
2791 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2792 // rtlight->photons = 0;
2794 // the user provided an energyperphoton value which we try to use
2795 // if that results in too many photons to shoot this frame, then we cap it
2796 // which causes photons to appear/disappear from frame to frame, so we don't
2797 // like doing that in the typical case
2798 normalphotonscaling = 1.0f / max(0.0001f, settings->energyperphoton);
2799 maxphotonscaling = (float)settings->maxphotons / max(1, photoncount);
2800 *photonscaling = min(normalphotonscaling, maxphotonscaling);
2803 static int R_Shadow_BounceGrid_SplatPathCompare(const void *pa, const void *pb)
2805 r_shadow_bouncegrid_splatpath_t *a = (r_shadow_bouncegrid_splatpath_t *)pa;
2806 r_shadow_bouncegrid_splatpath_t *b = (r_shadow_bouncegrid_splatpath_t *)pb;
2807 // we only really care about sorting by Z
2808 if (a->point[2] < b->point[2])
2810 if (a->point[2] > b->point[2])
2815 static void R_Shadow_BounceGrid_ClearPixels(void)
2817 // clear the highpixels array we'll be accumulating into
2818 r_shadow_bouncegrid_state.highpixels = (float *)R_FrameData_Alloc(r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2819 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2822 static void R_Shadow_BounceGrid_PerformSplats(void)
2824 int splatsize = r_shadow_bouncegrid_state.settings.lightpathsize;
2825 int splatsize1 = splatsize + 1;
2826 r_shadow_bouncegrid_splatpath_t *splatpaths = r_shadow_bouncegrid_state.splatpaths;
2827 r_shadow_bouncegrid_splatpath_t *splatpath;
2828 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2829 int numsplatpaths = r_shadow_bouncegrid_state.numsplatpaths;
2835 float texlerp[MAXBOUNCEGRIDSPLATSIZE1][3];
2836 float splatcolor[32];
2837 float boxweight = 1.0f / (splatsize * splatsize * splatsize);
2840 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2841 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2845 // hush warnings about uninitialized data - pixelbands doesn't change but...
2846 memset(splatcolor, 0, sizeof(splatcolor));
2848 // we use this a lot, so get a local copy
2849 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2851 // sort the splats before we execute them, to reduce cache misses
2852 if (r_shadow_bouncegrid_sortlightpaths.integer)
2853 qsort(splatpaths, numsplatpaths, sizeof(*splatpaths), R_Shadow_BounceGrid_SplatPathCompare);
2855 // the middle row/column/layer of each splat are full intensity
2856 for (step = 1;step < splatsize;step++)
2857 VectorSet(texlerp[step], 1.0f, 1.0f, 1.0f);
2859 splatpath = splatpaths;
2860 for (splatindex = 0;splatindex < numsplatpaths;splatindex++, splatpath++)
2862 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2863 // accumulate average shotcolor
2864 VectorCopy(splatpath->splatdir, dir);
2865 splatcolor[ 0] = splatpath->splatcolor[0];
2866 splatcolor[ 1] = splatpath->splatcolor[1];
2867 splatcolor[ 2] = splatpath->splatcolor[2];
2868 splatcolor[ 3] = 0.0f;
2871 // store bentnormal in case the shader has a use for it,
2872 // bentnormal is an intensity-weighted average of the directions,
2873 // and will be normalized on conversion to texture pixels.
2874 splatcolor[ 4] = dir[0] * splatpath->splatintensity;
2875 splatcolor[ 5] = dir[1] * splatpath->splatintensity;
2876 splatcolor[ 6] = dir[2] * splatpath->splatintensity;
2877 splatcolor[ 7] = splatpath->splatintensity;
2878 // for each color component (R, G, B) calculate the amount that a
2879 // direction contributes
2880 splatcolor[ 8] = splatcolor[0] * max(0.0f, dir[0]);
2881 splatcolor[ 9] = splatcolor[0] * max(0.0f, dir[1]);
2882 splatcolor[10] = splatcolor[0] * max(0.0f, dir[2]);
2883 splatcolor[11] = 0.0f;
2884 splatcolor[12] = splatcolor[1] * max(0.0f, dir[0]);
2885 splatcolor[13] = splatcolor[1] * max(0.0f, dir[1]);
2886 splatcolor[14] = splatcolor[1] * max(0.0f, dir[2]);
2887 splatcolor[15] = 0.0f;
2888 splatcolor[16] = splatcolor[2] * max(0.0f, dir[0]);
2889 splatcolor[17] = splatcolor[2] * max(0.0f, dir[1]);
2890 splatcolor[18] = splatcolor[2] * max(0.0f, dir[2]);
2891 splatcolor[19] = 0.0f;
2892 // and do the same for negative directions
2893 splatcolor[20] = splatcolor[0] * max(0.0f, -dir[0]);
2894 splatcolor[21] = splatcolor[0] * max(0.0f, -dir[1]);
2895 splatcolor[22] = splatcolor[0] * max(0.0f, -dir[2]);
2896 splatcolor[23] = 0.0f;
2897 splatcolor[24] = splatcolor[1] * max(0.0f, -dir[0]);
2898 splatcolor[25] = splatcolor[1] * max(0.0f, -dir[1]);
2899 splatcolor[26] = splatcolor[1] * max(0.0f, -dir[2]);
2900 splatcolor[27] = 0.0f;
2901 splatcolor[28] = splatcolor[2] * max(0.0f, -dir[0]);
2902 splatcolor[29] = splatcolor[2] * max(0.0f, -dir[1]);
2903 splatcolor[30] = splatcolor[2] * max(0.0f, -dir[2]);
2904 splatcolor[31] = 0.0f;
2906 // calculate the number of steps we need to traverse this distance
2907 VectorCopy(splatpath->point, steppos);
2908 VectorCopy(splatpath->step, stepdelta);
2909 numsteps = splatpath->remainingsplats;
2910 for (step = 0;step < numsteps;step++)
2912 r_refdef.stats[r_stat_bouncegrid_splats]++;
2913 // figure out the min corner of the pixels we'll need to update
2914 texcorner[0] = steppos[0] - (splatsize1 * 0.5f);
2915 texcorner[1] = steppos[1] - (splatsize1 * 0.5f);
2916 texcorner[2] = steppos[2] - (splatsize1 * 0.5f);
2917 tex[0] = (int)floor(texcorner[0]);
2918 tex[1] = (int)floor(texcorner[1]);
2919 tex[2] = (int)floor(texcorner[2]);
2920 // only update if it is within reasonable bounds
2924 && tex[0] < resolution[0] - splatsize1
2925 && tex[1] < resolution[1] - splatsize1
2926 && tex[2] < resolution[2] - splatsize1)
2928 // it is within bounds... do the real work now
2931 // calculate the antialiased box edges
2932 texlerp[splatsize][0] = texcorner[0] - tex[0];
2933 texlerp[splatsize][1] = texcorner[1] - tex[1];
2934 texlerp[splatsize][2] = texcorner[2] - tex[2];
2935 texlerp[0][0] = 1.0f - texlerp[splatsize][0];
2936 texlerp[0][1] = 1.0f - texlerp[splatsize][1];
2937 texlerp[0][2] = 1.0f - texlerp[splatsize][2];
2939 // accumulate light onto the pixels
2940 for (zi = 0;zi < splatsize1;zi++)
2942 for (yi = 0;yi < splatsize1;yi++)
2944 int index = ((tex[2]+zi)*resolution[1]+tex[1]+yi)*resolution[0]+tex[0];
2945 for (xi = 0;xi < splatsize1;xi++, index++)
2947 float w = texlerp[xi][0]*texlerp[yi][1]*texlerp[zi][2] * boxweight;
2949 float *p = highpixels + 4 * index + band * pixelsperband * 4;
2950 for (;band < pixelbands;band++, p += pixelsperband * 4)
2952 // add to the pixel color
2953 p[0] += splatcolor[band*4+0] * w;
2954 p[1] += splatcolor[band*4+1] * w;
2955 p[2] += splatcolor[band*4+2] * w;
2956 p[3] += splatcolor[band*4+3] * w;
2962 VectorAdd(steppos, stepdelta, steppos);
2967 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
2969 const float *inpixel;
2971 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2974 unsigned int x, y, z;
2975 unsigned int resolution[3];
2976 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2977 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2979 for (z = 1;z < resolution[2]-1;z++)
2981 for (y = 1;y < resolution[1]-1;y++)
2984 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2985 inpixel = inpixels + 4*index;
2986 outpixel = outpixels + 4*index;
2987 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
2989 outpixel[0] = (inpixel[0] + inpixel[ off] + inpixel[0-off]) * (1.0f / 3.0);
2990 outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
2991 outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
2992 outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
2999 static void R_Shadow_BounceGrid_BlurPixels(void)
3001 float *highpixels = r_shadow_bouncegrid_state.highpixels;
3002 float *temppixels1 = (float *)R_FrameData_Alloc(r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
3003 float *temppixels2 = (float *)R_FrameData_Alloc(r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
3004 unsigned int resolution[3];
3006 if (!r_shadow_bouncegrid_blur.integer)
3009 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3012 R_Shadow_BounceGrid_BlurPixelsInDirection(highpixels, temppixels1, 4);
3014 R_Shadow_BounceGrid_BlurPixelsInDirection(temppixels1, temppixels2, resolution[0] * 4);
3016 R_Shadow_BounceGrid_BlurPixelsInDirection(temppixels2, highpixels, resolution[0] * resolution[1] * 4);
3019 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
3021 int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
3022 unsigned char *pixelsbgra8 = NULL;
3023 unsigned char *pixelbgra8;
3024 unsigned short *pixelsrgba16f = NULL;
3025 unsigned short *pixelrgba16f;
3026 float *pixelsrgba32f = NULL;
3027 float *highpixels = r_shadow_bouncegrid_state.highpixels;
3030 unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
3031 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
3032 unsigned int pixelband;
3033 unsigned int x, y, z;
3034 unsigned int index, bandindex;
3035 unsigned int resolution[3];
3037 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3039 if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
3041 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3042 r_shadow_bouncegrid_state.texture = NULL;
3045 // if bentnormals exist, we need to normalize and bias them for the shader
3049 for (z = 0;z < resolution[2]-1;z++)
3051 for (y = 0;y < resolution[1]-1;y++)
3054 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3055 highpixel = highpixels + 4*index;
3056 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3058 // only convert pixels that were hit by photons
3059 if (highpixel[3] != 0.0f)
3060 VectorNormalize(highpixel);
3061 VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
3062 highpixel[pixelsperband * 4 + 3] = 1.0f;
3068 // start by clearing the pixels array - we won't be writing to all of it
3070 // then process only the pixels that have at least some color, skipping
3071 // the higher bands for speed on pixels that are black
3072 switch (floatcolors)
3075 pixelsbgra8 = (unsigned char *)R_FrameData_Alloc(r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
3076 for (pixelband = 0;pixelband < pixelbands;pixelband++)
3079 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
3081 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
3083 for (z = 1;z < resolution[2]-1;z++)
3085 for (y = 1;y < resolution[1]-1;y++)
3089 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3090 highpixel = highpixels + 4*index;
3091 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3093 // only convert pixels that were hit by photons
3094 if (VectorLength2(highpixel))
3096 // normalize the bentnormal now
3099 VectorNormalize(highpixel + pixelsperband * 4);
3100 highpixel[pixelsperband * 4 + 3] = 1.0f;
3102 // process all of the pixelbands for this pixel
3103 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3105 pixelbgra8 = pixelsbgra8 + 4*bandindex;
3106 bandpixel = highpixels + 4*bandindex;
3107 c[0] = (int)(bandpixel[0]*256.0f);
3108 c[1] = (int)(bandpixel[1]*256.0f);
3109 c[2] = (int)(bandpixel[2]*256.0f);
3110 c[3] = (int)(bandpixel[3]*256.0f);
3111 pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
3112 pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
3113 pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
3114 pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
3121 if (!r_shadow_bouncegrid_state.createtexture)
3122 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3124 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);
3127 pixelsrgba16f = (unsigned short *)R_FrameData_Alloc(r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3128 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3129 for (z = 1;z < resolution[2]-1;z++)
3131 for (y = 1;y < resolution[1]-1;y++)
3135 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3136 highpixel = highpixels + 4*index;
3137 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3139 // only convert pixels that were hit by photons
3140 if (VectorLength2(highpixel))
3142 // process all of the pixelbands for this pixel
3143 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3145 // time to have fun with IEEE 754 bit hacking...
3148 unsigned int raw[4];
3150 pixelrgba16f = pixelsrgba16f + 4*bandindex;
3151 bandpixel = highpixels + 4*bandindex;
3152 VectorCopy4(bandpixel, u.f);
3153 VectorCopy4(u.raw, c);
3154 // this math supports negative numbers, snaps denormals to zero
3155 //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
3156 //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
3157 //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
3158 //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
3159 // this math does not support negative
3160 pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
3161 pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
3162 pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
3163 pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
3170 if (!r_shadow_bouncegrid_state.createtexture)
3171 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3173 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);
3176 // our native format happens to match, so this is easy.
3177 pixelsrgba32f = highpixels;
3179 if (!r_shadow_bouncegrid_state.createtexture)
3180 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3182 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);
3186 r_shadow_bouncegrid_state.lastupdatetime = realtime;
3189 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)
3193 int hitsupercontentsmask;
3198 //trace_t cliptrace2;
3199 //trace_t cliptrace3;
3200 unsigned int lightindex;
3201 unsigned int seed = (unsigned int)(realtime * 1000.0f);
3203 vec3_t baseshotcolor;
3212 // we'll need somewhere to store these
3213 r_shadow_bouncegrid_state.numsplatpaths = 0;
3214 r_shadow_bouncegrid_state.splatpaths = (r_shadow_bouncegrid_splatpath_t *)R_FrameData_Alloc(sizeof(r_shadow_bouncegrid_splatpath_t) * r_shadow_bouncegrid_state.maxsplatpaths);
3216 // figure out what we want to interact with
3217 if (settings.hitmodels)
3218 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;// | SUPERCONTENTS_LIQUIDSMASK;
3220 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
3221 maxbounce = settings.maxbounce;
3223 for (lightindex = 0;lightindex < range2;lightindex++)
3225 if (lightindex < range)
3227 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3230 rtlight = &light->rtlight;
3233 rtlight = r_refdef.scene.lights[lightindex - range];
3234 // note that this code used to keep track of residual photons and
3235 // distribute them evenly to achieve exactly a desired photon count,
3236 // but that caused unwanted flickering in dynamic mode
3237 shootparticles = (int)floor(rtlight->photons * photonscaling);
3238 // skip if we won't be shooting any photons
3239 if (!shootparticles)
3241 radius = rtlight->radius * settings.lightradiusscale;
3242 s = settings.particleintensity / shootparticles;
3243 VectorScale(rtlight->photoncolor, s, baseshotcolor);
3244 r_refdef.stats[r_stat_bouncegrid_lights]++;
3245 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
3246 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
3248 if (settings.stablerandom > 0)
3249 seed = lightindex * 11937 + shotparticles;
3250 VectorCopy(baseshotcolor, shotcolor);
3251 VectorCopy(rtlight->shadoworigin, clipstart);
3252 if (settings.stablerandom < 0)
3253 VectorRandom(clipend);
3255 VectorCheeseRandom(clipend);
3256 VectorMA(clipstart, radius, clipend, clipend);
3257 for (bouncecount = 0;;bouncecount++)
3259 r_refdef.stats[r_stat_bouncegrid_traces]++;
3260 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
3261 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
3262 if (settings.staticmode)
3264 // static mode fires a LOT of rays but none of them are identical, so they are not cached
3265 cliptrace = CL_TraceLine(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), NULL, hitsupercontentsmask, collision_extendmovelength.value, true, false, NULL, true, true);
3269 // dynamic mode fires many rays and most will match the cache from the previous frame
3270 cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask);
3272 if (bouncecount > 0 || settings.includedirectlighting)
3275 VectorCopy(cliptrace.endpos, hitpos);
3276 R_Shadow_BounceGrid_AddSplatPath(clipstart, hitpos, shotcolor);
3278 if (cliptrace.fraction >= 1.0f)
3280 r_refdef.stats[r_stat_bouncegrid_hits]++;
3281 if (bouncecount >= maxbounce)
3283 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
3284 // also clamp the resulting color to never add energy, even if the user requests extreme values
3285 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
3286 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
3288 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
3289 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
3290 surfcolor[0] = min(surfcolor[0], 1.0f);
3291 surfcolor[1] = min(surfcolor[1], 1.0f);
3292 surfcolor[2] = min(surfcolor[2], 1.0f);
3293 VectorMultiply(shotcolor, surfcolor, shotcolor);
3294 if (VectorLength2(baseshotcolor) == 0.0f)
3296 r_refdef.stats[r_stat_bouncegrid_bounces]++;
3297 if (settings.bounceanglediffuse)
3299 // random direction, primarily along plane normal
3300 s = VectorDistance(cliptrace.endpos, clipend);
3301 if (settings.stablerandom < 0)
3302 VectorRandom(clipend);
3304 VectorCheeseRandom(clipend);
3305 VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
3306 VectorNormalize(clipend);
3307 VectorScale(clipend, s, clipend);
3311 // reflect the remaining portion of the line across plane normal
3312 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
3313 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
3315 // calculate the new line start and end
3316 VectorCopy(cliptrace.endpos, clipstart);
3317 VectorAdd(clipstart, clipend, clipend);
3323 void R_Shadow_UpdateBounceGridTexture(void)
3325 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3326 r_shadow_bouncegrid_settings_t settings;
3327 qboolean enable = false;
3328 qboolean settingschanged;
3329 unsigned int range; // number of world lights
3330 unsigned int range1; // number of dynamic lights (or zero if disabled)
3331 unsigned int range2; // range+range1
3332 float photonscaling;
3334 enable = R_Shadow_BounceGrid_CheckEnable(flag);
3336 R_Shadow_BounceGrid_GenerateSettings(&settings);
3338 // changing intensity does not require an update
3339 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
3341 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
3343 // when settings change, we free everything as it is just simpler that way.
3344 if (settingschanged || !enable)
3346 // not enabled, make sure we free anything we don't need anymore.
3347 if (r_shadow_bouncegrid_state.texture)
3349 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3350 r_shadow_bouncegrid_state.texture = NULL;
3352 r_shadow_bouncegrid_state.numpixels = 0;
3353 r_shadow_bouncegrid_state.directional = false;
3359 // if all the settings seem identical to the previous update, return
3360 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
3363 // store the new settings
3364 r_shadow_bouncegrid_state.settings = settings;
3366 R_Shadow_BounceGrid_UpdateSpacing();
3368 // get the range of light numbers we'll be looping over:
3369 // range = static lights
3370 // range1 = dynamic lights (optional)
3371 // range2 = range + range1
3372 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3373 range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
3374 range2 = range + range1;
3376 // calculate weighting factors for distributing photons among the lights
3377 R_Shadow_BounceGrid_AssignPhotons(&settings, range, range1, range2, flag, &photonscaling);
3379 // trace the photons from lights and accumulate illumination
3380 R_Shadow_BounceGrid_TracePhotons(settings, range, range1, range2, photonscaling, flag);
3382 // clear the texture
3383 R_Shadow_BounceGrid_ClearPixels();
3385 // accumulate the light splatting into texture
3386 R_Shadow_BounceGrid_PerformSplats();
3388 // apply a mild blur filter to the texture
3389 R_Shadow_BounceGrid_BlurPixels();
3391 // convert the pixels to lower precision and upload the texture
3392 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
3395 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
3397 R_Shadow_RenderMode_Reset();
3398 GL_BlendFunc(GL_ONE, GL_ONE);
3399 GL_DepthRange(0, 1);
3400 GL_DepthTest(r_showshadowvolumes.integer < 2);
3401 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
3402 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
3403 GL_CullFace(GL_NONE);
3404 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
3407 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
3409 R_Shadow_RenderMode_Reset();
3410 GL_BlendFunc(GL_ONE, GL_ONE);
3411 GL_DepthRange(0, 1);
3412 GL_DepthTest(r_showlighting.integer < 2);
3413 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
3415 GL_DepthFunc(GL_EQUAL);
3416 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
3417 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
3420 void R_Shadow_RenderMode_End(void)
3422 R_Shadow_RenderMode_Reset();
3423 R_Shadow_RenderMode_ActiveLight(NULL);
3425 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3426 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3429 int bboxedges[12][2] =
3448 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
3450 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
3452 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
3453 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
3454 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
3455 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
3458 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
3459 return true; // invisible
3460 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
3461 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
3462 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
3463 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
3464 r_refdef.stats[r_stat_lights_scissored]++;
3468 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
3471 const float *vertex3f;
3472 const float *normal3f;
3474 float dist, dot, distintensity, shadeintensity, v[3], n[3];
3475 switch (r_shadow_rendermode)
3477 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3478 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3479 if (VectorLength2(diffusecolor) > 0)
3481 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)
3483 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3484 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3485 if ((dot = DotProduct(n, v)) < 0)
3487 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3488 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
3491 VectorCopy(ambientcolor, color4f);
3492 if (r_refdef.fogenabled)
3495 f = RSurf_FogVertex(vertex3f);
3496 VectorScale(color4f, f, color4f);
3503 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3505 VectorCopy(ambientcolor, color4f);
3506 if (r_refdef.fogenabled)
3509 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3510 f = RSurf_FogVertex(vertex3f);
3511 VectorScale(color4f + 4*i, f, color4f);
3517 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3518 if (VectorLength2(diffusecolor) > 0)
3520 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)
3522 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3523 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3525 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3526 if ((dot = DotProduct(n, v)) < 0)
3528 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3529 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3530 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3531 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3535 color4f[0] = ambientcolor[0] * distintensity;
3536 color4f[1] = ambientcolor[1] * distintensity;
3537 color4f[2] = ambientcolor[2] * distintensity;
3539 if (r_refdef.fogenabled)
3542 f = RSurf_FogVertex(vertex3f);
3543 VectorScale(color4f, f, color4f);
3547 VectorClear(color4f);
3553 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3555 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3556 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3558 color4f[0] = ambientcolor[0] * distintensity;
3559 color4f[1] = ambientcolor[1] * distintensity;
3560 color4f[2] = ambientcolor[2] * distintensity;
3561 if (r_refdef.fogenabled)
3564 f = RSurf_FogVertex(vertex3f);
3565 VectorScale(color4f, f, color4f);
3569 VectorClear(color4f);
3574 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3575 if (VectorLength2(diffusecolor) > 0)
3577 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)
3579 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3580 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3582 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3583 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3584 if ((dot = DotProduct(n, v)) < 0)
3586 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3587 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3588 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3589 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3593 color4f[0] = ambientcolor[0] * distintensity;
3594 color4f[1] = ambientcolor[1] * distintensity;
3595 color4f[2] = ambientcolor[2] * distintensity;
3597 if (r_refdef.fogenabled)
3600 f = RSurf_FogVertex(vertex3f);
3601 VectorScale(color4f, f, color4f);
3605 VectorClear(color4f);
3611 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3613 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3614 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3616 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3617 color4f[0] = ambientcolor[0] * distintensity;
3618 color4f[1] = ambientcolor[1] * distintensity;
3619 color4f[2] = ambientcolor[2] * distintensity;
3620 if (r_refdef.fogenabled)
3623 f = RSurf_FogVertex(vertex3f);
3624 VectorScale(color4f, f, color4f);
3628 VectorClear(color4f);
3638 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3640 // used to display how many times a surface is lit for level design purposes
3641 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3642 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3646 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
3648 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3649 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
3653 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3660 int newnumtriangles;
3664 int maxtriangles = 1024;
3665 int newelements[1024*3];
3666 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3667 for (renders = 0;renders < 4;renders++)
3672 newnumtriangles = 0;
3674 // due to low fillrate on the cards this vertex lighting path is
3675 // designed for, we manually cull all triangles that do not
3676 // contain a lit vertex
3677 // this builds batches of triangles from multiple surfaces and
3678 // renders them at once
3679 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3681 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3683 if (newnumtriangles)
3685 newfirstvertex = min(newfirstvertex, e[0]);
3686 newlastvertex = max(newlastvertex, e[0]);
3690 newfirstvertex = e[0];
3691 newlastvertex = e[0];
3693 newfirstvertex = min(newfirstvertex, e[1]);
3694 newlastvertex = max(newlastvertex, e[1]);
3695 newfirstvertex = min(newfirstvertex, e[2]);
3696 newlastvertex = max(newlastvertex, e[2]);
3702 if (newnumtriangles >= maxtriangles)
3704 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3705 newnumtriangles = 0;
3711 if (newnumtriangles >= 1)
3713 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3716 // if we couldn't find any lit triangles, exit early
3719 // now reduce the intensity for the next overbright pass
3720 // we have to clamp to 0 here incase the drivers have improper
3721 // handling of negative colors
3722 // (some old drivers even have improper handling of >1 color)
3724 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3726 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3728 c[0] = max(0, c[0] - 1);
3729 c[1] = max(0, c[1] - 1);
3730 c[2] = max(0, c[2] - 1);
3742 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
3744 // OpenGL 1.1 path (anything)
3745 float ambientcolorbase[3], diffusecolorbase[3];
3746 float ambientcolorpants[3], diffusecolorpants[3];
3747 float ambientcolorshirt[3], diffusecolorshirt[3];
3748 const float *surfacecolor = rsurface.texture->dlightcolor;
3749 const float *surfacepants = rsurface.colormap_pantscolor;
3750 const float *surfaceshirt = rsurface.colormap_shirtcolor;
3751 rtexture_t *basetexture = rsurface.texture->basetexture;
3752 rtexture_t *pantstexture = rsurface.texture->pantstexture;
3753 rtexture_t *shirttexture = rsurface.texture->shirttexture;
3754 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3755 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3756 ambientscale *= 2 * r_refdef.view.colorscale;
3757 diffusescale *= 2 * r_refdef.view.colorscale;
3758 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3759 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3760 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3761 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3762 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3763 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
3764 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3765 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
3766 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3767 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
3768 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
3769 R_Mesh_TexBind(0, basetexture);
3770 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
3771 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
3772 switch(r_shadow_rendermode)
3774 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3775 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
3776 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3777 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3778 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3780 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3781 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
3782 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
3783 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
3784 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3786 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3787 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
3788 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3789 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3790 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3792 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3797 //R_Mesh_TexBind(0, basetexture);
3798 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
3801 R_Mesh_TexBind(0, pantstexture);
3802 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
3806 R_Mesh_TexBind(0, shirttexture);
3807 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
3811 extern cvar_t gl_lightmaps;
3812 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3814 float ambientscale, diffusescale, specularscale;
3816 float lightcolor[3];
3817 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
3818 ambientscale = rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient;
3819 diffusescale = rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient);
3820 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3821 if (!r_shadow_usenormalmap.integer)
3823 ambientscale += 1.0f * diffusescale;
3827 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
3829 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
3832 VectorNegate(lightcolor, lightcolor);
3833 GL_BlendEquationSubtract(true);
3835 RSurf_SetupDepthAndCulling();
3836 switch (r_shadow_rendermode)
3838 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3839 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3840 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
3842 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3843 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
3845 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3846 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3847 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3848 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3849 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
3852 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3856 GL_BlendEquationSubtract(false);
3859 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)
3861 matrix4x4_t tempmatrix = *matrix;
3862 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3864 // if this light has been compiled before, free the associated data
3865 R_RTLight_Uncompile(rtlight);
3867 // clear it completely to avoid any lingering data
3868 memset(rtlight, 0, sizeof(*rtlight));
3870 // copy the properties
3871 rtlight->matrix_lighttoworld = tempmatrix;
3872 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3873 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3874 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3875 VectorCopy(color, rtlight->color);
3876 rtlight->cubemapname[0] = 0;
3877 if (cubemapname && cubemapname[0])
3878 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3879 rtlight->shadow = shadow;
3880 rtlight->corona = corona;
3881 rtlight->style = style;
3882 rtlight->isstatic = isstatic;
3883 rtlight->coronasizescale = coronasizescale;
3884 rtlight->ambientscale = ambientscale;
3885 rtlight->diffusescale = diffusescale;
3886 rtlight->specularscale = specularscale;
3887 rtlight->flags = flags;
3889 // compute derived data
3890 //rtlight->cullradius = rtlight->radius;
3891 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3892 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3893 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3894 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3895 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3896 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3897 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3900 // compiles rtlight geometry
3901 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3902 void R_RTLight_Compile(rtlight_t *rtlight)
3905 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3906 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3907 entity_render_t *ent = r_refdef.scene.worldentity;
3908 dp_model_t *model = r_refdef.scene.worldmodel;
3909 unsigned char *data;
3912 // compile the light
3913 rtlight->compiled = true;
3914 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3915 rtlight->static_numleafs = 0;
3916 rtlight->static_numleafpvsbytes = 0;
3917 rtlight->static_leaflist = NULL;
3918 rtlight->static_leafpvs = NULL;
3919 rtlight->static_numsurfaces = 0;
3920 rtlight->static_surfacelist = NULL;
3921 rtlight->static_shadowmap_receivers = 0x3F;
3922 rtlight->static_shadowmap_casters = 0x3F;
3923 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3924 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3925 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3926 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3927 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3928 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3930 if (model && model->GetLightInfo)
3932 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3933 r_shadow_compilingrtlight = rtlight;
3934 R_FrameData_SetMark();
3935 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);
3936 R_FrameData_ReturnToMark();
3937 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3938 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3939 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3940 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3941 rtlight->static_numsurfaces = numsurfaces;
3942 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3943 rtlight->static_numleafs = numleafs;
3944 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3945 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3946 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3947 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3948 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3949 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3950 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3951 if (rtlight->static_numsurfaces)
3952 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3953 if (rtlight->static_numleafs)
3954 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3955 if (rtlight->static_numleafpvsbytes)
3956 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3957 if (rtlight->static_numshadowtrispvsbytes)
3958 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3959 if (rtlight->static_numlighttrispvsbytes)
3960 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3961 R_FrameData_SetMark();
3962 switch (rtlight->shadowmode)
3964 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3965 if (model->CompileShadowMap && rtlight->shadow)
3966 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3969 if (model->CompileShadowVolume && rtlight->shadow)
3970 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3973 R_FrameData_ReturnToMark();
3974 // now we're done compiling the rtlight
3975 r_shadow_compilingrtlight = NULL;
3979 // use smallest available cullradius - box radius or light radius
3980 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3981 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3983 shadowzpasstris = 0;
3984 if (rtlight->static_meshchain_shadow_zpass)
3985 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3986 shadowzpasstris += mesh->numtriangles;
3988 shadowzfailtris = 0;
3989 if (rtlight->static_meshchain_shadow_zfail)
3990 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3991 shadowzfailtris += mesh->numtriangles;
3994 if (rtlight->static_numlighttrispvsbytes)
3995 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3996 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
4000 if (rtlight->static_numshadowtrispvsbytes)
4001 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
4002 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
4005 if (developer_extra.integer)
4006 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);
4009 void R_RTLight_Uncompile(rtlight_t *rtlight)
4011 if (rtlight->compiled)
4013 if (rtlight->static_meshchain_shadow_zpass)
4014 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
4015 rtlight->static_meshchain_shadow_zpass = NULL;
4016 if (rtlight->static_meshchain_shadow_zfail)
4017 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
4018 rtlight->static_meshchain_shadow_zfail = NULL;
4019 if (rtlight->static_meshchain_shadow_shadowmap)
4020 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
4021 rtlight->static_meshchain_shadow_shadowmap = NULL;
4022 // these allocations are grouped
4023 if (rtlight->static_surfacelist)
4024 Mem_Free(rtlight->static_surfacelist);
4025 rtlight->static_numleafs = 0;
4026 rtlight->static_numleafpvsbytes = 0;
4027 rtlight->static_leaflist = NULL;
4028 rtlight->static_leafpvs = NULL;
4029 rtlight->static_numsurfaces = 0;
4030 rtlight->static_surfacelist = NULL;
4031 rtlight->static_numshadowtrispvsbytes = 0;
4032 rtlight->static_shadowtrispvs = NULL;
4033 rtlight->static_numlighttrispvsbytes = 0;
4034 rtlight->static_lighttrispvs = NULL;
4035 rtlight->compiled = false;
4039 void R_Shadow_UncompileWorldLights(void)
4043 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4044 for (lightindex = 0;lightindex < range;lightindex++)
4046 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4049 R_RTLight_Uncompile(&light->rtlight);
4053 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
4057 // reset the count of frustum planes
4058 // see rtlight->cached_frustumplanes definition for how much this array
4060 rtlight->cached_numfrustumplanes = 0;
4062 if (r_trippy.integer)
4065 // haven't implemented a culling path for ortho rendering
4066 if (!r_refdef.view.useperspective)
4068 // check if the light is on screen and copy the 4 planes if it is
4069 for (i = 0;i < 4;i++)
4070 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4073 for (i = 0;i < 4;i++)
4074 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4079 // generate a deformed frustum that includes the light origin, this is
4080 // used to cull shadow casting surfaces that can not possibly cast a
4081 // shadow onto the visible light-receiving surfaces, which can be a
4084 // if the light origin is onscreen the result will be 4 planes exactly
4085 // if the light origin is offscreen on only one axis the result will
4086 // be exactly 5 planes (split-side case)
4087 // if the light origin is offscreen on two axes the result will be
4088 // exactly 4 planes (stretched corner case)
4089 for (i = 0;i < 4;i++)
4091 // quickly reject standard frustum planes that put the light
4092 // origin outside the frustum
4093 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4096 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4098 // if all the standard frustum planes were accepted, the light is onscreen
4099 // otherwise we need to generate some more planes below...
4100 if (rtlight->cached_numfrustumplanes < 4)
4102 // at least one of the stock frustum planes failed, so we need to
4103 // create one or two custom planes to enclose the light origin
4104 for (i = 0;i < 4;i++)
4106 // create a plane using the view origin and light origin, and a
4107 // single point from the frustum corner set
4108 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
4109 VectorNormalize(plane.normal);
4110 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
4111 // see if this plane is backwards and flip it if so
4112 for (j = 0;j < 4;j++)
4113 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4117 VectorNegate(plane.normal, plane.normal);
4119 // flipped plane, test again to see if it is now valid
4120 for (j = 0;j < 4;j++)
4121 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4123 // if the plane is still not valid, then it is dividing the
4124 // frustum and has to be rejected
4128 // we have created a valid plane, compute extra info
4129 PlaneClassify(&plane);
4131 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4133 // if we've found 5 frustum planes then we have constructed a
4134 // proper split-side case and do not need to keep searching for
4135 // planes to enclose the light origin
4136 if (rtlight->cached_numfrustumplanes == 5)
4144 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
4146 plane = rtlight->cached_frustumplanes[i];
4147 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));
4152 // now add the light-space box planes if the light box is rotated, as any
4153 // caster outside the oriented light box is irrelevant (even if it passed
4154 // the worldspace light box, which is axial)
4155 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
4157 for (i = 0;i < 6;i++)
4161 v[i >> 1] = (i & 1) ? -1 : 1;
4162 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
4163 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
4164 plane.dist = VectorNormalizeLength(plane.normal);
4165 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
4166 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4172 // add the world-space reduced box planes
4173 for (i = 0;i < 6;i++)
4175 VectorClear(plane.normal);
4176 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
4177 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
4178 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4187 // reduce all plane distances to tightly fit the rtlight cull box, which
4189 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4190 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4191 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4192 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4193 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4194 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4195 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4196 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4197 oldnum = rtlight->cached_numfrustumplanes;
4198 rtlight->cached_numfrustumplanes = 0;
4199 for (j = 0;j < oldnum;j++)
4201 // find the nearest point on the box to this plane
4202 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
4203 for (i = 1;i < 8;i++)
4205 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
4206 if (bestdist > dist)
4209 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);
4210 // if the nearest point is near or behind the plane, we want this
4211 // plane, otherwise the plane is useless as it won't cull anything
4212 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
4214 PlaneClassify(&rtlight->cached_frustumplanes[j]);
4215 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
4222 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
4226 RSurf_ActiveWorldEntity();
4228 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4231 GL_CullFace(GL_NONE);
4232 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
4233 for (;mesh;mesh = mesh->next)
4235 if (!mesh->sidetotals[r_shadow_shadowmapside])
4237 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
4238 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4239 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);
4243 else if (r_refdef.scene.worldentity->model)
4244 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);
4246 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4249 static void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
4251 qboolean zpass = false;
4254 int surfacelistindex;
4255 msurface_t *surface;
4257 // if triangle neighbors are disabled, shadowvolumes are disabled
4258 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
4261 RSurf_ActiveWorldEntity();
4263 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4266 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
4268 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
4269 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
4271 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
4272 for (;mesh;mesh = mesh->next)
4274 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->numtriangles;
4275 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4276 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
4278 // increment stencil if frontface is infront of depthbuffer
4279 GL_CullFace(r_refdef.view.cullface_back);
4280 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
4281 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);
4282 // decrement stencil if backface is infront of depthbuffer
4283 GL_CullFace(r_refdef.view.cullface_front);
4284 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
4286 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
4288 // decrement stencil if backface is behind depthbuffer
4289 GL_CullFace(r_refdef.view.cullface_front);
4290 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
4291 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);
4292 // increment stencil if frontface is behind depthbuffer
4293 GL_CullFace(r_refdef.view.cullface_back);
4294 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
4296 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);
4300 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
4302 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
4303 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
4304 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
4306 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
4307 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
4308 if (CHECKPVSBIT(trispvs, t))
4309 shadowmarklist[numshadowmark++] = t;
4311 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);
4313 else if (numsurfaces)
4315 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);
4318 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4321 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
4323 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
4324 vec_t relativeshadowradius;
4325 RSurf_ActiveModelEntity(ent, false, false, false);
4326 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
4327 // we need to re-init the shader for each entity because the matrix changed
4328 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
4329 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
4330 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
4331 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
4332 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
4333 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
4334 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
4335 switch (r_shadow_rendermode)
4337 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
4338 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4341 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4344 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4347 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
4349 // set up properties for rendering light onto this entity
4350 RSurf_ActiveModelEntity(ent, true, true, false);
4351 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
4352 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4353 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4354 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4357 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
4359 if (!r_refdef.scene.worldmodel->DrawLight)
4362 // set up properties for rendering light onto this entity
4363 RSurf_ActiveWorldEntity();
4364 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
4365 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4366 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4367 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4369 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
4371 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4374 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
4376 dp_model_t *model = ent->model;
4377 if (!model->DrawLight)
4380 R_Shadow_SetupEntityLight(ent);
4382 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
4384 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4387 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
4391 int numleafs, numsurfaces;
4392 int *leaflist, *surfacelist;
4393 unsigned char *leafpvs;
4394 unsigned char *shadowtrispvs;
4395 unsigned char *lighttrispvs;
4396 //unsigned char *surfacesides;
4397 int numlightentities;
4398 int numlightentities_noselfshadow;
4399 int numshadowentities;
4400 int numshadowentities_noselfshadow;
4401 // FIXME: bounds check lightentities and shadowentities, etc.
4402 static entity_render_t *lightentities[MAX_EDICTS];
4403 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
4404 static entity_render_t *shadowentities[MAX_EDICTS];
4405 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
4407 qboolean castshadows;
4409 rtlight->draw = false;
4410 rtlight->cached_numlightentities = 0;
4411 rtlight->cached_numlightentities_noselfshadow = 0;
4412 rtlight->cached_numshadowentities = 0;
4413 rtlight->cached_numshadowentities_noselfshadow = 0;
4414 rtlight->cached_numsurfaces = 0;
4415 rtlight->cached_lightentities = NULL;
4416 rtlight->cached_lightentities_noselfshadow = NULL;
4417 rtlight->cached_shadowentities = NULL;
4418 rtlight->cached_shadowentities_noselfshadow = NULL;
4419 rtlight->cached_shadowtrispvs = NULL;
4420 rtlight->cached_lighttrispvs = NULL;
4421 rtlight->cached_surfacelist = NULL;
4422 rtlight->shadowmapsidesize = 0;
4424 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
4425 // skip lights that are basically invisible (color 0 0 0)
4426 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
4428 // loading is done before visibility checks because loading should happen
4429 // all at once at the start of a level, not when it stalls gameplay.
4430 // (especially important to benchmarks)
4432 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
4434 if (rtlight->compiled)
4435 R_RTLight_Uncompile(rtlight);
4436 R_RTLight_Compile(rtlight);
4440 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
4442 // look up the light style value at this time
4443 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4444 VectorScale(rtlight->color, f, rtlight->currentcolor);
4446 if (rtlight->selected)
4448 f = 2 + sin(realtime * M_PI * 4.0);
4449 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
4453 // if lightstyle is currently off, don't draw the light
4454 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
4457 // skip processing on corona-only lights
4461 // if the light box is offscreen, skip it
4462 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
4465 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
4466 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
4468 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4470 // 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
4471 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
4474 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
4476 // compiled light, world available and can receive realtime lighting
4477 // retrieve leaf information
4478 numleafs = rtlight->static_numleafs;
4479 leaflist = rtlight->static_leaflist;
4480 leafpvs = rtlight->static_leafpvs;
4481 numsurfaces = rtlight->static_numsurfaces;
4482 surfacelist = rtlight->static_surfacelist;
4483 //surfacesides = NULL;
4484 shadowtrispvs = rtlight->static_shadowtrispvs;
4485 lighttrispvs = rtlight->static_lighttrispvs;
4487 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4489 // dynamic light, world available and can receive realtime lighting
4490 // calculate lit surfaces and leafs
4491 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);
4492 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4493 leaflist = r_shadow_buffer_leaflist;
4494 leafpvs = r_shadow_buffer_leafpvs;
4495 surfacelist = r_shadow_buffer_surfacelist;
4496 //surfacesides = r_shadow_buffer_surfacesides;
4497 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4498 lighttrispvs = r_shadow_buffer_lighttrispvs;
4499 // if the reduced leaf bounds are offscreen, skip it
4500 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4511 //surfacesides = NULL;
4512 shadowtrispvs = NULL;
4513 lighttrispvs = NULL;
4515 // check if light is illuminating any visible leafs
4518 for (i = 0; i < numleafs; i++)
4519 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4525 // make a list of lit entities and shadow casting entities
4526 numlightentities = 0;
4527 numlightentities_noselfshadow = 0;
4528 numshadowentities = 0;
4529 numshadowentities_noselfshadow = 0;
4531 // add dynamic entities that are lit by the light
4532 for (i = 0; i < r_refdef.scene.numentities; i++)
4535 entity_render_t *ent = r_refdef.scene.entities[i];
4537 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4539 // skip the object entirely if it is not within the valid
4540 // shadow-casting region (which includes the lit region)
4541 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
4543 if (!(model = ent->model))
4545 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4547 // this entity wants to receive light, is visible, and is
4548 // inside the light box
4549 // TODO: check if the surfaces in the model can receive light
4550 // so now check if it's in a leaf seen by the light
4551 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))
4553 if (ent->flags & RENDER_NOSELFSHADOW)
4554 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
4556 lightentities[numlightentities++] = ent;
4557 // since it is lit, it probably also casts a shadow...
4558 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4559 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4560 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4562 // note: exterior models without the RENDER_NOSELFSHADOW
4563 // flag still create a RENDER_NOSELFSHADOW shadow but
4564 // are lit normally, this means that they are
4565 // self-shadowing but do not shadow other
4566 // RENDER_NOSELFSHADOW entities such as the gun
4567 // (very weird, but keeps the player shadow off the gun)
4568 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4569 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4571 shadowentities[numshadowentities++] = ent;
4574 else if (ent->flags & RENDER_SHADOW)
4576 // this entity is not receiving light, but may still need to
4578 // TODO: check if the surfaces in the model can cast shadow
4579 // now check if it is in a leaf seen by the light
4580 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))
4582 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4583 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4584 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4586 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4587 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4589 shadowentities[numshadowentities++] = ent;
4594 // return if there's nothing at all to light
4595 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4598 // count this light in the r_speeds
4599 r_refdef.stats[r_stat_lights]++;
4601 // flag it as worth drawing later
4602 rtlight->draw = true;
4604 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
4605 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4607 numshadowentities = numshadowentities_noselfshadow = 0;
4608 rtlight->castshadows = castshadows;
4610 // cache all the animated entities that cast a shadow but are not visible
4611 for (i = 0; i < numshadowentities; i++)
4612 R_AnimCache_GetEntity(shadowentities[i], false, false);
4613 for (i = 0; i < numshadowentities_noselfshadow; i++)
4614 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4616 // 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)
4617 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
4619 for (i = 0; i < numshadowentities_noselfshadow; i++)
4620 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
4621 numshadowentities_noselfshadow = 0;
4624 // we can convert noselfshadow to regular if there are no casters of that type
4625 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
4627 for (i = 0; i < numlightentities_noselfshadow; i++)
4628 lightentities[numlightentities++] = lightentities_noselfshadow[i];
4629 numlightentities_noselfshadow = 0;
4632 // allocate some temporary memory for rendering this light later in the frame
4633 // reusable buffers need to be copied, static data can be used as-is
4634 rtlight->cached_numlightentities = numlightentities;
4635 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
4636 rtlight->cached_numshadowentities = numshadowentities;
4637 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4638 rtlight->cached_numsurfaces = numsurfaces;
4639 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4640 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4641 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4642 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4643 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4645 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4646 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4647 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4648 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4649 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4653 // compiled light data
4654 rtlight->cached_shadowtrispvs = shadowtrispvs;
4655 rtlight->cached_lighttrispvs = lighttrispvs;
4656 rtlight->cached_surfacelist = surfacelist;
4659 if (R_Shadow_ShadowMappingEnabled())
4661 // figure out the shadowmapping parameters for this light
4662 vec3_t nearestpoint;
4665 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4666 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4667 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4668 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4669 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
4670 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4671 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4672 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4673 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
4677 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
4681 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4682 int numlightentities;
4683 int numlightentities_noselfshadow;
4684 int numshadowentities;
4685 int numshadowentities_noselfshadow;
4686 entity_render_t **lightentities;
4687 entity_render_t **lightentities_noselfshadow;
4688 entity_render_t **shadowentities;
4689 entity_render_t **shadowentities_noselfshadow;
4691 static unsigned char entitysides[MAX_EDICTS];
4692 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4698 matrix4x4_t radiustolight;
4700 // check if we cached this light this frame (meaning it is worth drawing)
4701 if (!rtlight->draw || !rtlight->castshadows)
4704 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
4705 if (rtlight->shadowmapatlassidesize == 0)
4707 rtlight->castshadows = false;
4711 // set up a scissor rectangle for this light
4712 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4715 // don't let sound skip if going slow
4716 if (r_refdef.scene.extraupdate)
4719 numlightentities = rtlight->cached_numlightentities;
4720 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4721 numshadowentities = rtlight->cached_numshadowentities;
4722 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4723 numsurfaces = rtlight->cached_numsurfaces;
4724 lightentities = rtlight->cached_lightentities;
4725 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4726 shadowentities = rtlight->cached_shadowentities;
4727 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4728 shadowtrispvs = rtlight->cached_shadowtrispvs;
4729 lighttrispvs = rtlight->cached_lighttrispvs;
4730 surfacelist = rtlight->cached_surfacelist;
4732 // make this the active rtlight for rendering purposes
4733 R_Shadow_RenderMode_ActiveLight(rtlight);
4735 radiustolight = rtlight->matrix_worldtolight;
4736 Matrix4x4_Abs(&radiustolight);
4738 size = rtlight->shadowmapatlassidesize;
4739 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4741 surfacesides = NULL;
4746 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4748 castermask = rtlight->static_shadowmap_casters;
4749 receivermask = rtlight->static_shadowmap_receivers;
4753 surfacesides = r_shadow_buffer_surfacesides;
4754 for (i = 0; i < numsurfaces; i++)
4756 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4757 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4758 castermask |= surfacesides[i];
4759 receivermask |= surfacesides[i];
4764 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
4765 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4766 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
4767 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4769 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4773 for (i = 0; i < numshadowentities; i++)
4774 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4775 for (i = 0; i < numshadowentities_noselfshadow; i++)
4776 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4779 // there is no need to render shadows for sides that have no receivers...
4780 castermask &= receivermask;
4782 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
4784 // render shadow casters into shadowmaps for this light
4785 for (side = 0; side < 6; side++)
4787 int bit = 1 << side;
4788 if (castermask & bit)
4790 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
4792 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4793 for (i = 0; i < numshadowentities; i++)
4794 if (entitysides[i] & bit)
4795 R_Shadow_DrawEntityShadow(shadowentities[i]);
4796 for (i = 0; i < numshadowentities_noselfshadow; i++)
4797 if (entitysides_noselfshadow[i] & bit)
4798 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4801 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
4802 if (numshadowentities_noselfshadow)
4804 for (side = 0; side < 6; side++)
4806 int bit = 1 << side;
4807 if (castermask & bit)
4809 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
4811 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4812 for (i = 0; i < numshadowentities; i++)
4813 if (entitysides[i] & bit)
4814 R_Shadow_DrawEntityShadow(shadowentities[i]);
4820 static void R_Shadow_DrawLight(rtlight_t *rtlight)
4824 unsigned char *shadowtrispvs, *lighttrispvs;
4825 int numlightentities;
4826 int numlightentities_noselfshadow;
4827 int numshadowentities;
4828 int numshadowentities_noselfshadow;
4829 entity_render_t **lightentities;
4830 entity_render_t **lightentities_noselfshadow;
4831 entity_render_t **shadowentities;
4832 entity_render_t **shadowentities_noselfshadow;
4834 qboolean castshadows;
4836 // check if we cached this light this frame (meaning it is worth drawing)
4840 // set up a scissor rectangle for this light
4841 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4844 // don't let sound skip if going slow
4845 if (r_refdef.scene.extraupdate)
4848 numlightentities = rtlight->cached_numlightentities;
4849 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4850 numshadowentities = rtlight->cached_numshadowentities;
4851 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4852 numsurfaces = rtlight->cached_numsurfaces;
4853 lightentities = rtlight->cached_lightentities;
4854 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4855 shadowentities = rtlight->cached_shadowentities;
4856 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4857 shadowtrispvs = rtlight->cached_shadowtrispvs;
4858 lighttrispvs = rtlight->cached_lighttrispvs;
4859 surfacelist = rtlight->cached_surfacelist;
4860 castshadows = rtlight->castshadows;
4862 // make this the active rtlight for rendering purposes
4863 R_Shadow_RenderMode_ActiveLight(rtlight);
4865 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4867 // optionally draw visible shape of the shadow volumes
4868 // for performance analysis by level designers
4869 R_Shadow_RenderMode_VisibleShadowVolumes();
4871 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4872 for (i = 0;i < numshadowentities;i++)
4873 R_Shadow_DrawEntityShadow(shadowentities[i]);
4874 for (i = 0;i < numshadowentities_noselfshadow;i++)
4875 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4876 R_Shadow_RenderMode_VisibleLighting(false, false);
4879 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4881 // optionally draw the illuminated areas
4882 // for performance analysis by level designers
4883 R_Shadow_RenderMode_VisibleLighting(false, false);
4885 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4886 for (i = 0;i < numlightentities;i++)
4887 R_Shadow_DrawEntityLight(lightentities[i]);
4888 for (i = 0;i < numlightentities_noselfshadow;i++)
4889 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4892 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4896 float shadowmapoffsetnoselfshadow = 0;
4897 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4898 Matrix4x4_Abs(&radiustolight);
4900 size = rtlight->shadowmapatlassidesize;
4901 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4903 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
4905 if (rtlight->cached_numshadowentities_noselfshadow)
4906 shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
4908 // render lighting using the depth texture as shadowmap
4909 // draw lighting in the unmasked areas
4910 if (numsurfaces + numlightentities)
4912 R_Shadow_RenderMode_Lighting(false, false, true, false);
4913 // draw lighting in the unmasked areas
4915 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4916 for (i = 0; i < numlightentities; i++)
4917 R_Shadow_DrawEntityLight(lightentities[i]);
4919 // offset to the noselfshadow part of the atlas and draw those too
4920 if (numlightentities_noselfshadow)
4922 R_Shadow_RenderMode_Lighting(false, false, true, true);
4923 for (i = 0; i < numlightentities_noselfshadow; i++)
4924 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4927 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
4928 if (r_shadow_usingdeferredprepass)
4929 R_Shadow_RenderMode_DrawDeferredLight(true);
4931 else if (castshadows && vid.stencil)
4933 // draw stencil shadow volumes to mask off pixels that are in shadow
4934 // so that they won't receive lighting
4935 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4936 R_Shadow_ClearStencil();
4939 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4940 for (i = 0;i < numshadowentities;i++)
4941 R_Shadow_DrawEntityShadow(shadowentities[i]);
4943 // draw lighting in the unmasked areas
4944 R_Shadow_RenderMode_Lighting(true, false, false, false);
4945 for (i = 0;i < numlightentities_noselfshadow;i++)
4946 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4948 for (i = 0;i < numshadowentities_noselfshadow;i++)
4949 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4951 // draw lighting in the unmasked areas
4952 R_Shadow_RenderMode_Lighting(true, false, false, false);
4954 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4955 for (i = 0;i < numlightentities;i++)
4956 R_Shadow_DrawEntityLight(lightentities[i]);
4958 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
4959 if (r_shadow_usingdeferredprepass)
4960 R_Shadow_RenderMode_DrawDeferredLight(false);
4964 // draw lighting in the unmasked areas
4965 R_Shadow_RenderMode_Lighting(false, false, false, false);
4967 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4968 for (i = 0;i < numlightentities;i++)
4969 R_Shadow_DrawEntityLight(lightentities[i]);
4970 for (i = 0;i < numlightentities_noselfshadow;i++)
4971 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4973 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
4974 if (r_shadow_usingdeferredprepass)
4975 R_Shadow_RenderMode_DrawDeferredLight(false);
4979 static void R_Shadow_FreeDeferred(void)
4981 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
4982 r_shadow_prepassgeometryfbo = 0;
4984 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
4985 r_shadow_prepasslightingdiffusespecularfbo = 0;
4987 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
4988 r_shadow_prepasslightingdiffusefbo = 0;
4990 if (r_shadow_prepassgeometrydepthbuffer)
4991 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
4992 r_shadow_prepassgeometrydepthbuffer = NULL;
4994 if (r_shadow_prepassgeometrynormalmaptexture)
4995 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4996 r_shadow_prepassgeometrynormalmaptexture = NULL;
4998 if (r_shadow_prepasslightingdiffusetexture)
4999 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
5000 r_shadow_prepasslightingdiffusetexture = NULL;
5002 if (r_shadow_prepasslightingspeculartexture)
5003 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
5004 r_shadow_prepasslightingspeculartexture = NULL;
5007 void R_Shadow_DrawPrepass(void)
5011 entity_render_t *ent;
5012 float clearcolor[4];
5014 R_Mesh_ResetTextureState();
5016 GL_ColorMask(1,1,1,1);
5017 GL_BlendFunc(GL_ONE, GL_ZERO);
5020 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5021 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
5022 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
5023 if (r_timereport_active)
5024 R_TimeReport("prepasscleargeom");
5026 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
5027 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
5028 if (r_timereport_active)
5029 R_TimeReport("prepassworld");
5031 for (i = 0;i < r_refdef.scene.numentities;i++)
5033 if (!r_refdef.viewcache.entityvisible[i])
5035 ent = r_refdef.scene.entities[i];
5036 if (ent->model && ent->model->DrawPrepass != NULL)
5037 ent->model->DrawPrepass(ent);
5040 if (r_timereport_active)
5041 R_TimeReport("prepassmodels");
5043 GL_DepthMask(false);
5044 GL_ColorMask(1,1,1,1);
5047 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5048 Vector4Set(clearcolor, 0, 0, 0, 0);
5049 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
5050 if (r_timereport_active)
5051 R_TimeReport("prepassclearlit");
5053 R_Shadow_RenderMode_Begin();
5055 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5056 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5058 R_Shadow_RenderMode_End();
5060 if (r_timereport_active)
5061 R_TimeReport("prepasslights");
5064 #define MAX_SCENELIGHTS 65536
5065 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
5067 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
5069 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
5071 r_shadow_scenemaxlights *= 2;
5072 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
5073 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
5075 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
5079 void R_Shadow_DrawLightSprites(void);
5080 void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
5089 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
5090 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
5091 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
5093 if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
5094 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
5095 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
5096 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
5097 r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) ||
5098 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
5099 r_shadow_shadowmapborder != shadowmapborder ||
5100 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
5101 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
5102 R_Shadow_FreeShadowMaps();
5104 r_shadow_fb_fbo = fbo;
5105 r_shadow_fb_depthtexture = depthtexture;
5106 r_shadow_fb_colortexture = colortexture;
5108 r_shadow_usingshadowmaportho = false;
5110 switch (vid.renderpath)
5112 case RENDERPATH_GL20:
5113 case RENDERPATH_D3D9:
5114 case RENDERPATH_D3D10:
5115 case RENDERPATH_D3D11:
5116 case RENDERPATH_SOFT:
5118 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
5120 r_shadow_usingdeferredprepass = false;
5121 if (r_shadow_prepass_width)
5122 R_Shadow_FreeDeferred();
5123 r_shadow_prepass_width = r_shadow_prepass_height = 0;
5127 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
5129 R_Shadow_FreeDeferred();
5131 r_shadow_usingdeferredprepass = true;
5132 r_shadow_prepass_width = vid.width;
5133 r_shadow_prepass_height = vid.height;
5134 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
5135 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);
5136 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);
5137 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);
5139 // set up the geometry pass fbo (depth + normalmap)
5140 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5141 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5142 // render depth into a renderbuffer and other important properties into the normalmap texture
5144 // set up the lighting pass fbo (diffuse + specular)
5145 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5146 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5147 // render diffuse into one texture and specular into another,
5148 // with depth and normalmap bound as textures,
5149 // with depth bound as attachment as well
5151 // set up the lighting pass fbo (diffuse)
5152 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5153 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5154 // render diffuse into one texture,
5155 // with depth and normalmap bound as textures,
5156 // with depth bound as attachment as well
5160 case RENDERPATH_GL11:
5161 case RENDERPATH_GL13:
5162 case RENDERPATH_GLES1:
5163 case RENDERPATH_GLES2:
5164 r_shadow_usingdeferredprepass = false;
5168 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);
5170 r_shadow_scenenumlights = 0;
5171 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5172 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5173 for (lightindex = 0; lightindex < range; lightindex++)
5175 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5176 if (light && (light->flags & flag))
5178 R_Shadow_PrepareLight(&light->rtlight);
5179 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5182 if (r_refdef.scene.rtdlight)
5184 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5186 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
5187 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
5190 else if (gl_flashblend.integer)
5192 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5194 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
5195 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
5196 VectorScale(rtlight->color, f, rtlight->currentcolor);
5200 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
5201 if (r_shadow_debuglight.integer >= 0)
5203 r_shadow_scenenumlights = 0;
5204 lightindex = r_shadow_debuglight.integer;
5205 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5208 R_Shadow_PrepareLight(&light->rtlight);
5209 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5213 // if we're doing shadowmaps we need to prepare the atlas layout now
5214 if (R_Shadow_ShadowMappingEnabled())
5218 // allocate shadowmaps in the atlas now
5219 // 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...
5220 for (lod = 0; lod < 16; lod++)
5222 int packing_success = 0;
5223 int packing_failure = 0;
5224 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
5225 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
5226 if (r_shadow_shadowmapatlas_modelshadows_size)
5227 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);
5228 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5230 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
5231 int size = rtlight->shadowmapsidesize >> lod;
5233 if (!rtlight->castshadows)
5235 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
5238 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
5239 if (rtlight->cached_numshadowentities_noselfshadow)
5241 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
5243 rtlight->shadowmapatlassidesize = size;
5248 // note down that we failed to pack this one, it will have to disable shadows
5249 rtlight->shadowmapatlassidesize = 0;
5253 // generally everything fits and we stop here on the first iteration
5254 if (packing_failure == 0)
5259 if (r_editlights.integer)
5260 R_Shadow_DrawLightSprites();
5263 void R_Shadow_DrawShadowMaps(void)
5265 R_Shadow_RenderMode_Begin();
5266 R_Shadow_RenderMode_ActiveLight(NULL);
5268 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
5269 R_Shadow_ClearShadowMapTexture();
5271 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
5272 if (r_shadow_shadowmapatlas_modelshadows_size)
5274 R_Shadow_DrawModelShadowMaps();
5275 // don't let sound skip if going slow
5276 if (r_refdef.scene.extraupdate)
5280 if (R_Shadow_ShadowMappingEnabled())
5283 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5284 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
5287 R_Shadow_RenderMode_End();
5290 void R_Shadow_DrawLights(void)
5294 R_Shadow_RenderMode_Begin();
5296 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5297 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5299 R_Shadow_RenderMode_End();
5302 #define MAX_MODELSHADOWS 1024
5303 static int r_shadow_nummodelshadows;
5304 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
5306 void R_Shadow_PrepareModelShadows(void)
5309 float scale, size, radius, dot1, dot2;
5310 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5311 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
5312 entity_render_t *ent;
5314 r_shadow_nummodelshadows = 0;
5315 r_shadow_shadowmapatlas_modelshadows_size = 0;
5317 if (!r_refdef.scene.numentities || r_refdef.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
5320 switch (r_shadow_shadowmode)
5322 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
5323 if (r_shadows.integer >= 2)
5326 case R_SHADOW_SHADOWMODE_STENCIL:
5329 for (i = 0; i < r_refdef.scene.numentities; i++)
5331 ent = r_refdef.scene.entities[i];
5332 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5334 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5336 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5337 R_AnimCache_GetEntity(ent, false, false);
5345 size = 2 * r_shadow_shadowmapmaxsize;
5346 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
5347 radius = 0.5f * size / scale;
5349 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5350 VectorCopy(prvmshadowdir, shadowdir);
5351 VectorNormalize(shadowdir);
5352 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5353 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5354 if (fabs(dot1) <= fabs(dot2))
5355 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5357 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5358 VectorNormalize(shadowforward);
5359 CrossProduct(shadowdir, shadowforward, shadowright);
5360 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5361 VectorCopy(prvmshadowfocus, shadowfocus);
5362 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5363 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5364 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5365 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5366 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5368 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5370 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5371 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5372 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5373 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5374 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5375 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5377 for (i = 0; i < r_refdef.scene.numentities; i++)
5379 ent = r_refdef.scene.entities[i];
5380 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
5382 // cast shadows from anything of the map (submodels are optional)
5383 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5385 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5387 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5388 R_AnimCache_GetEntity(ent, false, false);
5392 if (r_shadow_nummodelshadows)
5394 r_shadow_shadowmapatlas_modelshadows_x = 0;
5395 r_shadow_shadowmapatlas_modelshadows_y = 0;
5396 r_shadow_shadowmapatlas_modelshadows_size = size;
5400 static void R_Shadow_DrawModelShadowMaps(void)
5403 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
5404 entity_render_t *ent;
5405 vec3_t relativelightorigin;
5406 vec3_t relativelightdirection, relativeforward, relativeright;
5407 vec3_t relativeshadowmins, relativeshadowmaxs;
5408 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
5409 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5411 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
5412 r_viewport_t viewport;
5414 size = r_shadow_shadowmapatlas_modelshadows_size;
5415 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
5416 radius = 0.5f / scale;
5417 nearclip = -r_shadows_throwdistance.value;
5418 farclip = r_shadows_throwdistance.value;
5419 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);
5421 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
5422 r_shadow_modelshadowmap_parameters[0] = size;
5423 r_shadow_modelshadowmap_parameters[1] = size;
5424 r_shadow_modelshadowmap_parameters[2] = 1.0;
5425 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
5426 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
5427 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
5428 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
5429 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
5430 r_shadow_usingshadowmaportho = true;
5432 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5433 VectorCopy(prvmshadowdir, shadowdir);
5434 VectorNormalize(shadowdir);
5435 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5436 VectorCopy(prvmshadowfocus, shadowfocus);
5437 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5438 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5439 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5440 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5441 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5442 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5443 if (fabs(dot1) <= fabs(dot2))
5444 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5446 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5447 VectorNormalize(shadowforward);
5448 VectorM(scale, shadowforward, &m[0]);
5449 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5451 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
5452 CrossProduct(shadowdir, shadowforward, shadowright);
5453 VectorM(scale, shadowright, &m[4]);
5454 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
5455 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
5456 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
5457 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
5458 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
5459 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);
5460 R_SetViewport(&viewport);
5462 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5464 // render into a slightly restricted region so that the borders of the
5465 // shadowmap area fade away, rather than streaking across everything
5466 // outside the usable area
5467 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
5469 for (i = 0;i < r_shadow_nummodelshadows;i++)
5471 ent = r_shadow_modelshadows[i];
5472 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5473 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
5474 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5475 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
5476 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
5477 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5478 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5479 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5480 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5481 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5482 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5483 RSurf_ActiveModelEntity(ent, false, false, false);
5484 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
5485 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5491 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
5493 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
5495 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
5496 Cvar_SetValueQuick(&r_test, 0);
5501 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
5502 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
5503 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
5504 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
5505 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
5506 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
5508 switch (vid.renderpath)
5510 case RENDERPATH_GL11:
5511 case RENDERPATH_GL13:
5512 case RENDERPATH_GL20:
5513 case RENDERPATH_SOFT:
5514 case RENDERPATH_GLES1:
5515 case RENDERPATH_GLES2:
5517 case RENDERPATH_D3D9:
5518 case RENDERPATH_D3D10:
5519 case RENDERPATH_D3D11:
5520 #ifdef MATRIX4x4_OPENGLORIENTATION
5521 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5522 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
5523 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
5524 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
5526 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5527 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
5528 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
5529 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
5535 void R_Shadow_DrawModelShadows(void)
5538 float relativethrowdistance;
5539 entity_render_t *ent;
5540 vec3_t relativelightorigin;
5541 vec3_t relativelightdirection;
5542 vec3_t relativeshadowmins, relativeshadowmaxs;
5543 vec3_t tmp, shadowdir;
5544 prvm_vec3_t prvmshadowdir;
5546 if (!r_shadow_nummodelshadows || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
5549 R_ResetViewRendering3D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5550 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
5551 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5552 R_Shadow_RenderMode_Begin();
5553 R_Shadow_RenderMode_ActiveLight(NULL);
5554 r_shadow_lightscissor[0] = r_refdef.view.x;
5555 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
5556 r_shadow_lightscissor[2] = r_refdef.view.width;
5557 r_shadow_lightscissor[3] = r_refdef.view.height;
5558 R_Shadow_RenderMode_StencilShadowVolumes(false);
5561 if (r_shadows.integer == 2)
5563 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5564 VectorCopy(prvmshadowdir, shadowdir);
5565 VectorNormalize(shadowdir);
5568 R_Shadow_ClearStencil();
5570 for (i = 0;i < r_shadow_nummodelshadows;i++)
5572 ent = r_shadow_modelshadows[i];
5574 // cast shadows from anything of the map (submodels are optional)
5575 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5576 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
5577 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
5578 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
5579 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5582 if(ent->entitynumber != 0)
5584 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
5586 // FIXME handle this
5587 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5591 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
5592 int entnum, entnum2, recursion;
5593 entnum = entnum2 = ent->entitynumber;
5594 for(recursion = 32; recursion > 0; --recursion)
5596 entnum2 = cl.entities[entnum].state_current.tagentity;
5597 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
5602 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
5604 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
5605 // transform into modelspace of OUR entity
5606 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
5607 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
5610 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5614 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5617 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
5618 RSurf_ActiveModelEntity(ent, false, false, false);
5619 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
5620 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5623 // not really the right mode, but this will disable any silly stencil features
5624 R_Shadow_RenderMode_End();
5626 // set up ortho view for rendering this pass
5627 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5628 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5629 //GL_ScissorTest(true);
5630 //R_EntityMatrix(&identitymatrix);
5631 //R_Mesh_ResetTextureState();
5632 R_ResetViewRendering2D(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture);
5634 // set up a darkening blend on shadowed areas
5635 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5636 //GL_DepthRange(0, 1);
5637 //GL_DepthTest(false);
5638 //GL_DepthMask(false);
5639 //GL_PolygonOffset(0, 0);CHECKGLERROR
5640 GL_Color(0, 0, 0, r_shadows_darken.value);
5641 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5642 //GL_DepthFunc(GL_ALWAYS);
5643 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5645 // apply the blend to the shadowed areas
5646 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5647 R_SetupShader_Generic_NoTexture(false, true);
5648 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5650 // restore the viewport
5651 R_SetViewport(&r_refdef.view.viewport);
5653 // restore other state to normal
5654 //R_Shadow_RenderMode_End();
5657 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5660 vec3_t centerorigin;
5661 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5664 // if it's too close, skip it
5665 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5667 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5670 if (usequery && r_numqueries + 2 <= r_maxqueries)
5672 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5673 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5674 // 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
5675 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5677 switch(vid.renderpath)
5679 case RENDERPATH_GL11:
5680 case RENDERPATH_GL13:
5681 case RENDERPATH_GL20:
5682 case RENDERPATH_GLES1:
5683 case RENDERPATH_GLES2:
5684 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5686 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5687 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5688 GL_DepthFunc(GL_ALWAYS);
5689 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5690 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5691 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5692 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5693 GL_DepthFunc(GL_LEQUAL);
5694 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5695 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5696 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5697 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5698 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5702 case RENDERPATH_D3D9:
5703 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5705 case RENDERPATH_D3D10:
5706 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5708 case RENDERPATH_D3D11:
5709 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5711 case RENDERPATH_SOFT:
5712 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5716 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5719 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5721 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5724 unsigned int occlude = 0;
5725 GLint allpixels = 0, visiblepixels = 0;
5727 // now we have to check the query result
5728 if (rtlight->corona_queryindex_visiblepixels)
5730 switch(vid.renderpath)
5732 case RENDERPATH_GL11:
5733 case RENDERPATH_GL13:
5734 case RENDERPATH_GL20:
5735 case RENDERPATH_GLES1:
5736 case RENDERPATH_GLES2:
5737 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5739 // See if we can use the GPU-side method to prevent implicit sync
5740 if (vid.support.arb_query_buffer_object) {
5741 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
5742 if (!r_shadow_occlusion_buf) {
5743 qglGenBuffersARB(1, &r_shadow_occlusion_buf);
5744 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5745 qglBufferDataARB(GL_QUERY_BUFFER_ARB, 8, NULL, GL_DYNAMIC_COPY);
5747 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5749 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(0));
5750 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4));
5751 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
5752 occlude = MATERIALFLAG_OCCLUDE;
5754 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5755 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5756 if (visiblepixels < 1 || allpixels < 1)
5758 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5760 cscale *= rtlight->corona_visibility;
5766 case RENDERPATH_D3D9:
5767 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5769 case RENDERPATH_D3D10:
5770 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5772 case RENDERPATH_D3D11:
5773 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5775 case RENDERPATH_SOFT:
5776 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5784 // FIXME: these traces should scan all render entities instead of cl.world
5785 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
5788 VectorScale(rtlight->currentcolor, cscale, color);
5789 if (VectorLength(color) > (1.0f / 256.0f))
5792 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
5795 VectorNegate(color, color);
5796 GL_BlendEquationSubtract(true);
5798 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5799 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);
5800 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
5802 GL_BlendEquationSubtract(false);
5806 void R_Shadow_DrawCoronas(void)
5809 qboolean usequery = false;
5814 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
5816 if (r_fb.water.renderingscene)
5818 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5819 R_EntityMatrix(&identitymatrix);
5821 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5823 // check occlusion of coronas
5824 // use GL_ARB_occlusion_query if available
5825 // otherwise use raytraces
5827 switch (vid.renderpath)
5829 case RENDERPATH_GL11:
5830 case RENDERPATH_GL13:
5831 case RENDERPATH_GL20:
5832 case RENDERPATH_GLES1:
5833 case RENDERPATH_GLES2:
5834 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
5835 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5838 GL_ColorMask(0,0,0,0);
5839 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
5840 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
5843 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
5844 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
5846 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
5849 RSurf_ActiveWorldEntity();
5850 GL_BlendFunc(GL_ONE, GL_ZERO);
5851 GL_CullFace(GL_NONE);
5852 GL_DepthMask(false);
5853 GL_DepthRange(0, 1);
5854 GL_PolygonOffset(0, 0);
5856 R_Mesh_ResetTextureState();
5857 R_SetupShader_Generic_NoTexture(false, false);
5861 case RENDERPATH_D3D9:
5863 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5865 case RENDERPATH_D3D10:
5866 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5868 case RENDERPATH_D3D11:
5869 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5871 case RENDERPATH_SOFT:
5873 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5876 for (lightindex = 0;lightindex < range;lightindex++)
5878 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5881 rtlight = &light->rtlight;
5882 rtlight->corona_visibility = 0;
5883 rtlight->corona_queryindex_visiblepixels = 0;
5884 rtlight->corona_queryindex_allpixels = 0;
5885 if (!(rtlight->flags & flag))
5887 if (rtlight->corona <= 0)
5889 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
5891 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5893 for (i = 0;i < r_refdef.scene.numlights;i++)
5895 rtlight = r_refdef.scene.lights[i];
5896 rtlight->corona_visibility = 0;
5897 rtlight->corona_queryindex_visiblepixels = 0;
5898 rtlight->corona_queryindex_allpixels = 0;
5899 if (!(rtlight->flags & flag))
5901 if (rtlight->corona <= 0)
5903 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5906 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5908 // now draw the coronas using the query data for intensity info
5909 for (lightindex = 0;lightindex < range;lightindex++)
5911 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5914 rtlight = &light->rtlight;
5915 if (rtlight->corona_visibility <= 0)
5917 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5919 for (i = 0;i < r_refdef.scene.numlights;i++)
5921 rtlight = r_refdef.scene.lights[i];
5922 if (rtlight->corona_visibility <= 0)
5924 if (gl_flashblend.integer)
5925 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
5927 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5933 static dlight_t *R_Shadow_NewWorldLight(void)
5935 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
5938 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)
5942 // 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
5944 // validate parameters
5948 // copy to light properties
5949 VectorCopy(origin, light->origin);
5950 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
5951 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
5952 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
5954 light->color[0] = max(color[0], 0);
5955 light->color[1] = max(color[1], 0);
5956 light->color[2] = max(color[2], 0);
5958 light->color[0] = color[0];
5959 light->color[1] = color[1];
5960 light->color[2] = color[2];
5961 light->radius = max(radius, 0);
5962 light->style = style;
5963 light->shadow = shadowenable;
5964 light->corona = corona;
5965 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
5966 light->coronasizescale = coronasizescale;
5967 light->ambientscale = ambientscale;
5968 light->diffusescale = diffusescale;
5969 light->specularscale = specularscale;
5970 light->flags = flags;
5972 // update renderable light data
5973 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
5974 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);
5977 static void R_Shadow_FreeWorldLight(dlight_t *light)
5979 if (r_shadow_selectedlight == light)
5980 r_shadow_selectedlight = NULL;
5981 R_RTLight_Uncompile(&light->rtlight);
5982 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
5985 void R_Shadow_ClearWorldLights(void)
5989 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5990 for (lightindex = 0;lightindex < range;lightindex++)
5992 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5994 R_Shadow_FreeWorldLight(light);
5996 r_shadow_selectedlight = NULL;
5999 static void R_Shadow_SelectLight(dlight_t *light)
6001 if (r_shadow_selectedlight)
6002 r_shadow_selectedlight->selected = false;
6003 r_shadow_selectedlight = light;
6004 if (r_shadow_selectedlight)
6005 r_shadow_selectedlight->selected = true;
6008 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6010 // this is never batched (there can be only one)
6012 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
6013 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6014 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6017 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6022 skinframe_t *skinframe;
6025 // this is never batched (due to the ent parameter changing every time)
6026 // so numsurfaces == 1 and surfacelist[0] == lightnumber
6027 const dlight_t *light = (dlight_t *)ent;
6030 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
6033 VectorScale(light->color, intensity, spritecolor);
6034 if (VectorLength(spritecolor) < 0.1732f)
6035 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
6036 if (VectorLength(spritecolor) > 1.0f)
6037 VectorNormalize(spritecolor);
6039 // draw light sprite
6040 if (light->cubemapname[0] && !light->shadow)
6041 skinframe = r_editlights_sprcubemapnoshadowlight;
6042 else if (light->cubemapname[0])
6043 skinframe = r_editlights_sprcubemaplight;
6044 else if (!light->shadow)
6045 skinframe = r_editlights_sprnoshadowlight;
6047 skinframe = r_editlights_sprlight;
6049 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);
6050 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6052 // draw selection sprite if light is selected
6053 if (light->selected)
6055 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6056 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6057 // VorteX todo: add normalmode/realtime mode light overlay sprites?
6061 void R_Shadow_DrawLightSprites(void)
6065 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6066 for (lightindex = 0;lightindex < range;lightindex++)
6068 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6070 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
6072 if (!r_editlights_lockcursor)
6073 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
6076 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
6081 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6082 if (lightindex >= range)
6084 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6087 rtlight = &light->rtlight;
6088 //if (!(rtlight->flags & flag))
6090 VectorCopy(rtlight->shadoworigin, origin);
6091 *radius = rtlight->radius;
6092 VectorCopy(rtlight->color, color);
6096 static void R_Shadow_SelectLightInView(void)
6098 float bestrating, rating, temp[3];
6102 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6106 if (r_editlights_lockcursor)
6108 for (lightindex = 0;lightindex < range;lightindex++)
6110 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6113 VectorSubtract(light->origin, r_refdef.view.origin, temp);
6114 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
6117 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
6118 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1.0f)
6120 bestrating = rating;
6125 R_Shadow_SelectLight(best);
6128 void R_Shadow_LoadWorldLights(void)
6130 int n, a, style, shadow, flags;
6131 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
6132 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
6133 if (cl.worldmodel == NULL)
6135 Con_Print("No map loaded.\n");
6138 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6139 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6149 for (;COM_Parse(t, true) && strcmp(
6150 if (COM_Parse(t, true))
6152 if (com_token[0] == '!')
6155 origin[0] = atof(com_token+1);
6158 origin[0] = atof(com_token);
6163 while (*s && *s != '\n' && *s != '\r')
6169 // check for modifier flags
6176 #if _MSC_VER >= 1400
6177 #define sscanf sscanf_s
6179 cubemapname[sizeof(cubemapname)-1] = 0;
6180 #if MAX_QPATH != 128
6181 #error update this code if MAX_QPATH changes
6183 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
6184 #if _MSC_VER >= 1400
6185 , sizeof(cubemapname)
6187 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
6190 flags = LIGHTFLAG_REALTIMEMODE;
6198 coronasizescale = 0.25f;
6200 VectorClear(angles);
6203 if (a < 9 || !strcmp(cubemapname, "\"\""))
6205 // remove quotes on cubemapname
6206 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
6209 namelen = strlen(cubemapname) - 2;
6210 memmove(cubemapname, cubemapname + 1, namelen);
6211 cubemapname[namelen] = '\0';
6215 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);
6218 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6226 Con_Printf("invalid rtlights file \"%s\"\n", name);
6227 Mem_Free(lightsstring);
6231 void R_Shadow_SaveWorldLights(void)
6235 size_t bufchars, bufmaxchars;
6237 char name[MAX_QPATH];
6238 char line[MAX_INPUTLINE];
6239 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
6240 // I hate lines which are 3 times my screen size :( --blub
6243 if (cl.worldmodel == NULL)
6245 Con_Print("No map loaded.\n");
6248 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6249 bufchars = bufmaxchars = 0;
6251 for (lightindex = 0;lightindex < range;lightindex++)
6253 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6256 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
6257 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);
6258 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
6259 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]);
6261 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);
6262 if (bufchars + strlen(line) > bufmaxchars)
6264 bufmaxchars = bufchars + strlen(line) + 2048;
6266 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
6270 memcpy(buf, oldbuf, bufchars);
6276 memcpy(buf + bufchars, line, strlen(line));
6277 bufchars += strlen(line);
6281 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
6286 void R_Shadow_LoadLightsFile(void)
6289 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
6290 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
6291 if (cl.worldmodel == NULL)
6293 Con_Print("No map loaded.\n");
6296 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
6297 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6305 while (*s && *s != '\n' && *s != '\r')
6311 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);
6315 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);
6318 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
6319 radius = bound(15, radius, 4096);
6320 VectorScale(color, (2.0f / (8388608.0f)), color);
6321 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6329 Con_Printf("invalid lights file \"%s\"\n", name);
6330 Mem_Free(lightsstring);
6334 // tyrlite/hmap2 light types in the delay field
6335 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
6337 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
6349 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
6350 char key[256], value[MAX_INPUTLINE];
6353 if (cl.worldmodel == NULL)
6355 Con_Print("No map loaded.\n");
6358 // try to load a .ent file first
6359 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
6360 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
6361 // and if that is not found, fall back to the bsp file entity string
6363 data = cl.worldmodel->brush.entities;
6366 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
6368 type = LIGHTTYPE_MINUSX;
6369 origin[0] = origin[1] = origin[2] = 0;
6370 originhack[0] = originhack[1] = originhack[2] = 0;
6371 angles[0] = angles[1] = angles[2] = 0;
6372 color[0] = color[1] = color[2] = 1;
6373 light[0] = light[1] = light[2] = 1;light[3] = 300;
6374 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
6384 if (!COM_ParseToken_Simple(&data, false, false, true))
6386 if (com_token[0] == '}')
6387 break; // end of entity
6388 if (com_token[0] == '_')
6389 strlcpy(key, com_token + 1, sizeof(key));
6391 strlcpy(key, com_token, sizeof(key));
6392 while (key[strlen(key)-1] == ' ') // remove trailing spaces
6393 key[strlen(key)-1] = 0;
6394 if (!COM_ParseToken_Simple(&data, false, false, true))
6396 strlcpy(value, com_token, sizeof(value));
6398 // now that we have the key pair worked out...
6399 if (!strcmp("light", key))
6401 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
6405 light[0] = vec[0] * (1.0f / 256.0f);
6406 light[1] = vec[0] * (1.0f / 256.0f);
6407 light[2] = vec[0] * (1.0f / 256.0f);
6413 light[0] = vec[0] * (1.0f / 255.0f);
6414 light[1] = vec[1] * (1.0f / 255.0f);
6415 light[2] = vec[2] * (1.0f / 255.0f);
6419 else if (!strcmp("delay", key))
6421 else if (!strcmp("origin", key))
6422 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
6423 else if (!strcmp("angle", key))
6424 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
6425 else if (!strcmp("angles", key))
6426 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
6427 else if (!strcmp("color", key))
6428 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
6429 else if (!strcmp("wait", key))
6430 fadescale = atof(value);
6431 else if (!strcmp("classname", key))
6433 if (!strncmp(value, "light", 5))
6436 if (!strcmp(value, "light_fluoro"))
6441 overridecolor[0] = 1;
6442 overridecolor[1] = 1;
6443 overridecolor[2] = 1;
6445 if (!strcmp(value, "light_fluorospark"))
6450 overridecolor[0] = 1;
6451 overridecolor[1] = 1;
6452 overridecolor[2] = 1;
6454 if (!strcmp(value, "light_globe"))
6459 overridecolor[0] = 1;
6460 overridecolor[1] = 0.8;
6461 overridecolor[2] = 0.4;
6463 if (!strcmp(value, "light_flame_large_yellow"))
6468 overridecolor[0] = 1;
6469 overridecolor[1] = 0.5;
6470 overridecolor[2] = 0.1;
6472 if (!strcmp(value, "light_flame_small_yellow"))
6477 overridecolor[0] = 1;
6478 overridecolor[1] = 0.5;
6479 overridecolor[2] = 0.1;
6481 if (!strcmp(value, "light_torch_small_white"))
6486 overridecolor[0] = 1;
6487 overridecolor[1] = 0.5;
6488 overridecolor[2] = 0.1;
6490 if (!strcmp(value, "light_torch_small_walltorch"))
6495 overridecolor[0] = 1;
6496 overridecolor[1] = 0.5;
6497 overridecolor[2] = 0.1;
6501 else if (!strcmp("style", key))
6502 style = atoi(value);
6503 else if (!strcmp("skin", key))
6504 skin = (int)atof(value);
6505 else if (!strcmp("pflags", key))
6506 pflags = (int)atof(value);
6507 //else if (!strcmp("effects", key))
6508 // effects = (int)atof(value);
6509 else if (cl.worldmodel->type == mod_brushq3)
6511 if (!strcmp("scale", key))
6512 lightscale = atof(value);
6513 if (!strcmp("fade", key))
6514 fadescale = atof(value);
6519 if (lightscale <= 0)
6523 if (color[0] == color[1] && color[0] == color[2])
6525 color[0] *= overridecolor[0];
6526 color[1] *= overridecolor[1];
6527 color[2] *= overridecolor[2];
6529 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
6530 color[0] = color[0] * light[0];
6531 color[1] = color[1] * light[1];
6532 color[2] = color[2] * light[2];
6535 case LIGHTTYPE_MINUSX:
6537 case LIGHTTYPE_RECIPX:
6539 VectorScale(color, (1.0f / 16.0f), color);
6541 case LIGHTTYPE_RECIPXX:
6543 VectorScale(color, (1.0f / 16.0f), color);
6546 case LIGHTTYPE_NONE:
6550 case LIGHTTYPE_MINUSXX:
6553 VectorAdd(origin, originhack, origin);
6555 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);
6558 Mem_Free(entfiledata);
6562 static void R_Shadow_SetCursorLocationForView(void)
6565 vec3_t dest, endpos;
6567 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
6568 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true);
6569 if (trace.fraction < 1)
6571 dist = trace.fraction * r_editlights_cursordistance.value;
6572 push = r_editlights_cursorpushback.value;
6576 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
6577 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
6581 VectorClear( endpos );
6583 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6584 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6585 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6588 void R_Shadow_UpdateWorldLightSelection(void)
6590 if (r_editlights.integer)
6592 R_Shadow_SetCursorLocationForView();
6593 R_Shadow_SelectLightInView();
6596 R_Shadow_SelectLight(NULL);
6599 static void R_Shadow_EditLights_Clear_f(void)
6601 R_Shadow_ClearWorldLights();
6604 void R_Shadow_EditLights_Reload_f(void)
6608 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
6609 R_Shadow_ClearWorldLights();
6610 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
6612 R_Shadow_LoadWorldLights();
6613 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6614 R_Shadow_LoadLightsFile();
6616 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
6618 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6619 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6623 static void R_Shadow_EditLights_Save_f(void)
6627 R_Shadow_SaveWorldLights();
6630 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6632 R_Shadow_ClearWorldLights();
6633 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6636 static void R_Shadow_EditLights_ImportLightsFile_f(void)
6638 R_Shadow_ClearWorldLights();
6639 R_Shadow_LoadLightsFile();
6642 static void R_Shadow_EditLights_Spawn_f(void)
6645 if (!r_editlights.integer)
6647 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6650 if (Cmd_Argc() != 1)
6652 Con_Print("r_editlights_spawn does not take parameters\n");
6655 color[0] = color[1] = color[2] = 1;
6656 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6659 static void R_Shadow_EditLights_Edit_f(void)
6661 vec3_t origin, angles, color;
6662 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6663 int style, shadows, flags, normalmode, realtimemode;
6664 char cubemapname[MAX_INPUTLINE];
6665 if (!r_editlights.integer)
6667 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6670 if (!r_shadow_selectedlight)
6672 Con_Print("No selected light.\n");
6675 VectorCopy(r_shadow_selectedlight->origin, origin);
6676 VectorCopy(r_shadow_selectedlight->angles, angles);
6677 VectorCopy(r_shadow_selectedlight->color, color);
6678 radius = r_shadow_selectedlight->radius;
6679 style = r_shadow_selectedlight->style;
6680 if (r_shadow_selectedlight->cubemapname)
6681 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6684 shadows = r_shadow_selectedlight->shadow;
6685 corona = r_shadow_selectedlight->corona;
6686 coronasizescale = r_shadow_selectedlight->coronasizescale;
6687 ambientscale = r_shadow_selectedlight->ambientscale;
6688 diffusescale = r_shadow_selectedlight->diffusescale;
6689 specularscale = r_shadow_selectedlight->specularscale;
6690 flags = r_shadow_selectedlight->flags;
6691 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6692 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6693 if (!strcmp(Cmd_Argv(1), "origin"))
6695 if (Cmd_Argc() != 5)
6697 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6700 origin[0] = atof(Cmd_Argv(2));
6701 origin[1] = atof(Cmd_Argv(3));
6702 origin[2] = atof(Cmd_Argv(4));
6704 else if (!strcmp(Cmd_Argv(1), "originscale"))
6706 if (Cmd_Argc() != 5)
6708 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6711 origin[0] *= atof(Cmd_Argv(2));
6712 origin[1] *= atof(Cmd_Argv(3));
6713 origin[2] *= atof(Cmd_Argv(4));
6715 else if (!strcmp(Cmd_Argv(1), "originx"))
6717 if (Cmd_Argc() != 3)
6719 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6722 origin[0] = atof(Cmd_Argv(2));
6724 else if (!strcmp(Cmd_Argv(1), "originy"))
6726 if (Cmd_Argc() != 3)
6728 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6731 origin[1] = atof(Cmd_Argv(2));
6733 else if (!strcmp(Cmd_Argv(1), "originz"))
6735 if (Cmd_Argc() != 3)
6737 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6740 origin[2] = atof(Cmd_Argv(2));
6742 else if (!strcmp(Cmd_Argv(1), "move"))
6744 if (Cmd_Argc() != 5)
6746 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6749 origin[0] += atof(Cmd_Argv(2));
6750 origin[1] += atof(Cmd_Argv(3));
6751 origin[2] += atof(Cmd_Argv(4));
6753 else if (!strcmp(Cmd_Argv(1), "movex"))
6755 if (Cmd_Argc() != 3)
6757 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6760 origin[0] += atof(Cmd_Argv(2));
6762 else if (!strcmp(Cmd_Argv(1), "movey"))
6764 if (Cmd_Argc() != 3)
6766 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6769 origin[1] += atof(Cmd_Argv(2));
6771 else if (!strcmp(Cmd_Argv(1), "movez"))
6773 if (Cmd_Argc() != 3)
6775 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6778 origin[2] += atof(Cmd_Argv(2));
6780 else if (!strcmp(Cmd_Argv(1), "angles"))
6782 if (Cmd_Argc() != 5)
6784 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6787 angles[0] = atof(Cmd_Argv(2));
6788 angles[1] = atof(Cmd_Argv(3));
6789 angles[2] = atof(Cmd_Argv(4));
6791 else if (!strcmp(Cmd_Argv(1), "anglesx"))
6793 if (Cmd_Argc() != 3)
6795 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6798 angles[0] = atof(Cmd_Argv(2));
6800 else if (!strcmp(Cmd_Argv(1), "anglesy"))
6802 if (Cmd_Argc() != 3)
6804 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6807 angles[1] = atof(Cmd_Argv(2));
6809 else if (!strcmp(Cmd_Argv(1), "anglesz"))
6811 if (Cmd_Argc() != 3)
6813 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6816 angles[2] = atof(Cmd_Argv(2));
6818 else if (!strcmp(Cmd_Argv(1), "color"))
6820 if (Cmd_Argc() != 5)
6822 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
6825 color[0] = atof(Cmd_Argv(2));
6826 color[1] = atof(Cmd_Argv(3));
6827 color[2] = atof(Cmd_Argv(4));
6829 else if (!strcmp(Cmd_Argv(1), "radius"))
6831 if (Cmd_Argc() != 3)
6833 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6836 radius = atof(Cmd_Argv(2));
6838 else if (!strcmp(Cmd_Argv(1), "colorscale"))
6840 if (Cmd_Argc() == 3)
6842 double scale = atof(Cmd_Argv(2));
6849 if (Cmd_Argc() != 5)
6851 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
6854 color[0] *= atof(Cmd_Argv(2));
6855 color[1] *= atof(Cmd_Argv(3));
6856 color[2] *= atof(Cmd_Argv(4));
6859 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
6861 if (Cmd_Argc() != 3)
6863 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6866 radius *= atof(Cmd_Argv(2));
6868 else if (!strcmp(Cmd_Argv(1), "style"))
6870 if (Cmd_Argc() != 3)
6872 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6875 style = atoi(Cmd_Argv(2));
6877 else if (!strcmp(Cmd_Argv(1), "cubemap"))
6881 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6884 if (Cmd_Argc() == 3)
6885 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
6889 else if (!strcmp(Cmd_Argv(1), "shadows"))
6891 if (Cmd_Argc() != 3)
6893 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6896 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6898 else if (!strcmp(Cmd_Argv(1), "corona"))
6900 if (Cmd_Argc() != 3)
6902 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6905 corona = atof(Cmd_Argv(2));
6907 else if (!strcmp(Cmd_Argv(1), "coronasize"))
6909 if (Cmd_Argc() != 3)
6911 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6914 coronasizescale = atof(Cmd_Argv(2));
6916 else if (!strcmp(Cmd_Argv(1), "ambient"))
6918 if (Cmd_Argc() != 3)
6920 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6923 ambientscale = atof(Cmd_Argv(2));
6925 else if (!strcmp(Cmd_Argv(1), "diffuse"))
6927 if (Cmd_Argc() != 3)
6929 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6932 diffusescale = atof(Cmd_Argv(2));
6934 else if (!strcmp(Cmd_Argv(1), "specular"))
6936 if (Cmd_Argc() != 3)
6938 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6941 specularscale = atof(Cmd_Argv(2));
6943 else if (!strcmp(Cmd_Argv(1), "normalmode"))
6945 if (Cmd_Argc() != 3)
6947 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6950 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6952 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
6954 if (Cmd_Argc() != 3)
6956 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6959 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6963 Con_Print("usage: r_editlights_edit [property] [value]\n");
6964 Con_Print("Selected light's properties:\n");
6965 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6966 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6967 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6968 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
6969 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
6970 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
6971 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
6972 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
6973 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
6974 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
6975 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
6976 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
6977 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
6978 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
6981 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
6982 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6985 static void R_Shadow_EditLights_EditAll_f(void)
6988 dlight_t *light, *oldselected;
6991 if (!r_editlights.integer)
6993 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
6997 oldselected = r_shadow_selectedlight;
6998 // EditLights doesn't seem to have a "remove" command or something so:
6999 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7000 for (lightindex = 0;lightindex < range;lightindex++)
7002 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7005 R_Shadow_SelectLight(light);
7006 R_Shadow_EditLights_Edit_f();
7008 // return to old selected (to not mess editing once selection is locked)
7009 R_Shadow_SelectLight(oldselected);
7012 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
7014 int lightnumber, lightcount;
7015 size_t lightindex, range;
7020 if (!r_editlights.integer)
7023 // update cvars so QC can query them
7024 if (r_shadow_selectedlight)
7026 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7027 Cvar_SetQuick(&r_editlights_current_origin, temp);
7028 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7029 Cvar_SetQuick(&r_editlights_current_angles, temp);
7030 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7031 Cvar_SetQuick(&r_editlights_current_color, temp);
7032 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
7033 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
7034 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
7035 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
7036 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
7037 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
7038 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
7039 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
7040 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
7041 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
7042 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
7045 // draw properties on screen
7046 if (!r_editlights_drawproperties.integer)
7048 x = vid_conwidth.value - 240;
7050 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
7053 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7054 for (lightindex = 0;lightindex < range;lightindex++)
7056 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7059 if (light == r_shadow_selectedlight)
7060 lightnumber = (int)lightindex;
7063 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;
7064 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;
7066 if (r_shadow_selectedlight == NULL)
7068 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;
7069 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;
7070 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;
7071 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;
7072 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;
7073 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;
7074 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;
7075 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;
7076 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;
7077 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;
7078 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;
7079 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;
7080 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;
7081 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;
7082 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;
7085 static void R_Shadow_EditLights_ToggleShadow_f(void)
7087 if (!r_editlights.integer)
7089 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7092 if (!r_shadow_selectedlight)
7094 Con_Print("No selected light.\n");
7097 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);
7100 static void R_Shadow_EditLights_ToggleCorona_f(void)
7102 if (!r_editlights.integer)
7104 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7107 if (!r_shadow_selectedlight)
7109 Con_Print("No selected light.\n");
7112 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);
7115 static void R_Shadow_EditLights_Remove_f(void)
7117 if (!r_editlights.integer)
7119 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
7122 if (!r_shadow_selectedlight)
7124 Con_Print("No selected light.\n");
7127 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
7128 r_shadow_selectedlight = NULL;
7131 static void R_Shadow_EditLights_Help_f(void)
7134 "Documentation on r_editlights system:\n"
7136 "r_editlights : enable/disable editing mode\n"
7137 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
7138 "r_editlights_cursorpushback : push back cursor this far from surface\n"
7139 "r_editlights_cursorpushoff : push cursor off surface this far\n"
7140 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
7141 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
7143 "r_editlights_help : this help\n"
7144 "r_editlights_clear : remove all lights\n"
7145 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
7146 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
7147 "r_editlights_save : save to .rtlights file\n"
7148 "r_editlights_spawn : create a light with default settings\n"
7149 "r_editlights_edit command : edit selected light - more documentation below\n"
7150 "r_editlights_remove : remove selected light\n"
7151 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
7152 "r_editlights_importlightentitiesfrommap : reload light entities\n"
7153 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
7155 "origin x y z : set light location\n"
7156 "originx x: set x component of light location\n"
7157 "originy y: set y component of light location\n"
7158 "originz z: set z component of light location\n"
7159 "move x y z : adjust light location\n"
7160 "movex x: adjust x component of light location\n"
7161 "movey y: adjust y component of light location\n"
7162 "movez z: adjust z component of light location\n"
7163 "angles x y z : set light angles\n"
7164 "anglesx x: set x component of light angles\n"
7165 "anglesy y: set y component of light angles\n"
7166 "anglesz z: set z component of light angles\n"
7167 "color r g b : set color of light (can be brighter than 1 1 1)\n"
7168 "radius radius : set radius (size) of light\n"
7169 "colorscale grey : multiply color of light (1 does nothing)\n"
7170 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
7171 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
7172 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
7173 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
7174 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
7175 "cubemap basename : set filter cubemap of light\n"
7176 "shadows 1/0 : turn on/off shadows\n"
7177 "corona n : set corona intensity\n"
7178 "coronasize n : set corona size (0-1)\n"
7179 "ambient n : set ambient intensity (0-1)\n"
7180 "diffuse n : set diffuse intensity (0-1)\n"
7181 "specular n : set specular intensity (0-1)\n"
7182 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
7183 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
7184 "<nothing> : print light properties to console\n"
7188 static void R_Shadow_EditLights_CopyInfo_f(void)
7190 if (!r_editlights.integer)
7192 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
7195 if (!r_shadow_selectedlight)
7197 Con_Print("No selected light.\n");
7200 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
7201 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
7202 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
7203 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
7204 if (r_shadow_selectedlight->cubemapname)
7205 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
7207 r_shadow_bufferlight.cubemapname[0] = 0;
7208 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
7209 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
7210 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
7211 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
7212 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
7213 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
7214 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
7217 static void R_Shadow_EditLights_PasteInfo_f(void)
7219 if (!r_editlights.integer)
7221 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
7224 if (!r_shadow_selectedlight)
7226 Con_Print("No selected light.\n");
7229 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);
7232 static void R_Shadow_EditLights_Lock_f(void)
7234 if (!r_editlights.integer)
7236 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
7239 if (r_editlights_lockcursor)
7241 r_editlights_lockcursor = false;
7244 if (!r_shadow_selectedlight)
7246 Con_Print("No selected light to lock on.\n");
7249 r_editlights_lockcursor = true;
7252 static void R_Shadow_EditLights_Init(void)
7254 Cvar_RegisterVariable(&r_editlights);
7255 Cvar_RegisterVariable(&r_editlights_cursordistance);
7256 Cvar_RegisterVariable(&r_editlights_cursorpushback);
7257 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
7258 Cvar_RegisterVariable(&r_editlights_cursorgrid);
7259 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
7260 Cvar_RegisterVariable(&r_editlights_drawproperties);
7261 Cvar_RegisterVariable(&r_editlights_current_origin);
7262 Cvar_RegisterVariable(&r_editlights_current_angles);
7263 Cvar_RegisterVariable(&r_editlights_current_color);
7264 Cvar_RegisterVariable(&r_editlights_current_radius);
7265 Cvar_RegisterVariable(&r_editlights_current_corona);
7266 Cvar_RegisterVariable(&r_editlights_current_coronasize);
7267 Cvar_RegisterVariable(&r_editlights_current_style);
7268 Cvar_RegisterVariable(&r_editlights_current_shadows);
7269 Cvar_RegisterVariable(&r_editlights_current_cubemap);
7270 Cvar_RegisterVariable(&r_editlights_current_ambient);
7271 Cvar_RegisterVariable(&r_editlights_current_diffuse);
7272 Cvar_RegisterVariable(&r_editlights_current_specular);
7273 Cvar_RegisterVariable(&r_editlights_current_normalmode);
7274 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
7275 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
7276 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
7277 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)");
7278 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
7279 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
7280 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
7281 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)");
7282 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
7283 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
7284 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
7285 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
7286 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
7287 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
7288 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)");
7289 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
7295 =============================================================================
7299 =============================================================================
7302 void R_LightPoint(float *color, const vec3_t p, const int flags)
7304 int i, numlights, flag;
7305 float f, relativepoint[3], dist, dist2, lightradius2;
7310 if (r_fullbright.integer)
7312 VectorSet(color, 1, 1, 1);
7318 if (flags & LP_LIGHTMAP)
7320 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7322 VectorClear(diffuse);
7323 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, color, diffuse, n);
7324 VectorAdd(color, diffuse, color);
7327 VectorSet(color, 1, 1, 1);
7328 color[0] += r_refdef.scene.ambient;
7329 color[1] += r_refdef.scene.ambient;
7330 color[2] += r_refdef.scene.ambient;
7333 if (flags & LP_RTWORLD)
7335 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7336 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7337 for (i = 0; i < numlights; i++)
7339 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7342 light = &dlight->rtlight;
7343 if (!(light->flags & flag))
7346 lightradius2 = light->radius * light->radius;
7347 VectorSubtract(light->shadoworigin, p, relativepoint);
7348 dist2 = VectorLength2(relativepoint);
7349 if (dist2 >= lightradius2)
7351 dist = sqrt(dist2) / light->radius;
7352 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7355 // todo: add to both ambient and diffuse
7356 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1)
7357 VectorMA(color, f, light->currentcolor, color);
7360 if (flags & LP_DYNLIGHT)
7363 for (i = 0;i < r_refdef.scene.numlights;i++)
7365 light = r_refdef.scene.lights[i];
7367 lightradius2 = light->radius * light->radius;
7368 VectorSubtract(light->shadoworigin, p, relativepoint);
7369 dist2 = VectorLength2(relativepoint);
7370 if (dist2 >= lightradius2)
7372 dist = sqrt(dist2) / light->radius;
7373 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7376 // todo: add to both ambient and diffuse
7377 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1)
7378 VectorMA(color, f, light->color, color);
7383 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
7385 int i, numlights, flag;
7388 float relativepoint[3];
7397 if (r_fullbright.integer)
7399 VectorSet(ambient, 1, 1, 1);
7400 VectorClear(diffuse);
7401 VectorClear(lightdir);
7405 if (flags == LP_LIGHTMAP)
7407 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7408 VectorClear(diffuse);
7409 VectorClear(lightdir);
7410 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7411 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
7413 VectorSet(ambient, 1, 1, 1);
7417 memset(sample, 0, sizeof(sample));
7418 VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7420 if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7423 VectorClear(tempambient);
7425 VectorClear(relativepoint);
7426 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
7427 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
7428 VectorScale(color, r_refdef.lightmapintensity, color);
7429 VectorAdd(sample, tempambient, sample);
7430 VectorMA(sample , 0.5f , color, sample );
7431 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7432 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7433 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7434 // calculate a weighted average light direction as well
7435 intensity = VectorLength(color);
7436 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7439 if (flags & LP_RTWORLD)
7441 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7442 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7443 for (i = 0; i < numlights; i++)
7445 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7448 light = &dlight->rtlight;
7449 if (!(light->flags & flag))
7452 lightradius2 = light->radius * light->radius;
7453 VectorSubtract(light->shadoworigin, p, relativepoint);
7454 dist2 = VectorLength2(relativepoint);
7455 if (dist2 >= lightradius2)
7457 dist = sqrt(dist2) / light->radius;
7458 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
7459 if (intensity <= 0.0f)
7461 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
7463 // scale down intensity to add to both ambient and diffuse
7464 //intensity *= 0.5f;
7465 VectorNormalize(relativepoint);
7466 VectorScale(light->currentcolor, intensity, color);
7467 VectorMA(sample , 0.5f , color, sample );
7468 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7469 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7470 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7471 // calculate a weighted average light direction as well
7472 intensity *= VectorLength(color);
7473 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7475 // FIXME: sample bouncegrid too!
7478 if (flags & LP_DYNLIGHT)
7481 for (i = 0;i < r_refdef.scene.numlights;i++)
7483 light = r_refdef.scene.lights[i];
7485 lightradius2 = light->radius * light->radius;
7486 VectorSubtract(light->shadoworigin, p, relativepoint);
7487 dist2 = VectorLength2(relativepoint);
7488 if (dist2 >= lightradius2)
7490 dist = sqrt(dist2) / light->radius;
7491 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
7492 if (intensity <= 0.0f)
7494 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
7496 // scale down intensity to add to both ambient and diffuse
7497 //intensity *= 0.5f;
7498 VectorNormalize(relativepoint);
7499 VectorScale(light->currentcolor, intensity, color);
7500 VectorMA(sample , 0.5f , color, sample );
7501 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7502 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7503 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7504 // calculate a weighted average light direction as well
7505 intensity *= VectorLength(color);
7506 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7510 // calculate the direction we'll use to reduce the sample to a directional light source
7511 VectorCopy(sample + 12, dir);
7512 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
7513 VectorNormalize(dir);
7514 // extract the diffuse color along the chosen direction and scale it
7515 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
7516 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
7517 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
7518 // subtract some of diffuse from ambient
7519 VectorMA(sample, -0.333f, diffuse, ambient);
7520 // store the normalized lightdir
7521 VectorCopy(dir, lightdir);