3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however. Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light. This technique is used heavily in many games (Doom3 does not support
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
142 #include "dpsoftrast.h"
146 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
149 static void R_Shadow_EditLights_Init(void);
151 typedef enum r_shadow_rendermode_e
153 R_SHADOW_RENDERMODE_NONE,
154 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
155 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
156 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
157 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
158 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
159 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
160 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
161 R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN,
162 R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN,
163 R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN,
164 R_SHADOW_RENDERMODE_LIGHT_GLSL,
165 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
166 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
167 R_SHADOW_RENDERMODE_SHADOWMAP2D
169 r_shadow_rendermode_t;
171 typedef enum r_shadow_shadowmode_e
173 R_SHADOW_SHADOWMODE_STENCIL,
174 R_SHADOW_SHADOWMODE_SHADOWMAP2D
176 r_shadow_shadowmode_t;
178 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
180 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
181 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
182 int r_shadow_scenemaxlights;
183 int r_shadow_scenenumlights;
184 rtlight_t **r_shadow_scenelightlist; // includes both static lights and dlights, as filtered by appropriate flags
185 qboolean r_shadow_usingshadowmap2d;
186 qboolean r_shadow_usingshadowmaportho;
187 int r_shadow_shadowmapside;
188 float r_shadow_lightshadowmap_texturescale[4]; // xy = scale, zw = offset
189 float r_shadow_lightshadowmap_parameters[4]; // x = frustum width in pixels (excludes border), y = z scale, z = size of viewport, w = z center
190 float r_shadow_modelshadowmap_texturescale[4]; // xy = scale, zw = offset
191 float r_shadow_modelshadowmap_parameters[4]; // xyz = scale, w = shadow brightness
193 int r_shadow_drawbuffer;
194 int r_shadow_readbuffer;
196 int r_shadow_cullface_front, r_shadow_cullface_back;
197 GLuint r_shadow_fbo2d;
198 r_shadow_shadowmode_t r_shadow_shadowmode;
199 int r_shadow_shadowmapfilterquality;
200 int r_shadow_shadowmapdepthbits;
201 int r_shadow_shadowmapmaxsize;
202 int r_shadow_shadowmaptexturesize;
203 qboolean r_shadow_shadowmapvsdct;
204 qboolean r_shadow_shadowmapsampler;
205 qboolean r_shadow_shadowmapshadowsampler;
206 int r_shadow_shadowmappcf;
207 int r_shadow_shadowmapborder;
208 matrix4x4_t r_shadow_shadowmapmatrix;
209 int r_shadow_lightscissor[4];
210 qboolean r_shadow_usingdeferredprepass;
211 qboolean r_shadow_shadowmapdepthtexture;
212 mod_alloclightmap_state_t r_shadow_shadowmapatlas_state;
213 int r_shadow_shadowmapatlas_modelshadows_x;
214 int r_shadow_shadowmapatlas_modelshadows_y;
215 int r_shadow_shadowmapatlas_modelshadows_size;
216 int maxshadowtriangles;
219 int maxshadowvertices;
220 float *shadowvertex3f;
230 unsigned char *shadowsides;
231 int *shadowsideslist;
238 int r_shadow_buffer_numleafpvsbytes;
239 unsigned char *r_shadow_buffer_visitingleafpvs;
240 unsigned char *r_shadow_buffer_leafpvs;
241 int *r_shadow_buffer_leaflist;
243 int r_shadow_buffer_numsurfacepvsbytes;
244 unsigned char *r_shadow_buffer_surfacepvs;
245 int *r_shadow_buffer_surfacelist;
246 unsigned char *r_shadow_buffer_surfacesides;
248 int r_shadow_buffer_numshadowtrispvsbytes;
249 unsigned char *r_shadow_buffer_shadowtrispvs;
250 int r_shadow_buffer_numlighttrispvsbytes;
251 unsigned char *r_shadow_buffer_lighttrispvs;
253 rtexturepool_t *r_shadow_texturepool;
254 rtexture_t *r_shadow_attenuationgradienttexture;
255 rtexture_t *r_shadow_attenuation2dtexture;
256 rtexture_t *r_shadow_attenuation3dtexture;
257 skinframe_t *r_shadow_lightcorona;
258 rtexture_t *r_shadow_shadowmap2ddepthbuffer;
259 rtexture_t *r_shadow_shadowmap2ddepthtexture;
260 rtexture_t *r_shadow_shadowmapvsdcttexture;
262 GLuint r_shadow_prepassgeometryfbo;
263 GLuint r_shadow_prepasslightingdiffusespecularfbo;
264 GLuint r_shadow_prepasslightingdiffusefbo;
265 int r_shadow_prepass_width;
266 int r_shadow_prepass_height;
267 rtexture_t *r_shadow_prepassgeometrydepthbuffer;
268 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
269 rtexture_t *r_shadow_prepasslightingdiffusetexture;
270 rtexture_t *r_shadow_prepasslightingspeculartexture;
272 int r_shadow_viewfbo;
273 rtexture_t *r_shadow_viewdepthtexture;
274 rtexture_t *r_shadow_viewcolortexture;
277 int r_shadow_viewwidth;
278 int r_shadow_viewheight;
280 // lights are reloaded when this changes
281 char r_shadow_mapname[MAX_QPATH];
283 // buffer for doing corona fading
284 unsigned int r_shadow_occlusion_buf = 0;
286 // used only for light filters (cubemaps)
287 rtexturepool_t *r_shadow_filters_texturepool;
289 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
290 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
291 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
292 cvar_t r_shadow_deferred = {CVAR_SAVE, "r_shadow_deferred", "0", "uses image-based lighting instead of geometry-based lighting, the method used renders a depth image and a normalmap image, renders lights into separate diffuse and specular images, and then combines this into the normal rendering, requires r_shadow_shadowmapping"};
293 cvar_t r_shadow_usebihculling = {0, "r_shadow_usebihculling", "1", "use BIH (Bounding Interval Hierarchy) for culling lit surfaces instead of BSP (Binary Space Partitioning)"};
294 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
295 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
296 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
297 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
298 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
299 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
300 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
301 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
302 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
303 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
304 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
305 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
306 cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
307 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
308 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
309 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
310 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
311 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
312 cvar_t r_shadow_realtime_world_importlightentitiesfrommap = {0, "r_shadow_realtime_world_importlightentitiesfrommap", "1", "load lights from .ent file or map entities at startup if no .rtlights or .lights file is present (if set to 2, always use the .ent or map entities)"};
313 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
314 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
315 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
316 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
317 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation (slower than compileportalculling but more exact)"};
318 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
319 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
320 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "1", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes"};
321 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
322 cvar_t r_shadow_shadowmapping_useshadowsampler = {CVAR_SAVE, "r_shadow_shadowmapping_useshadowsampler", "1", "whether to use sampler2DShadow if available"};
323 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
324 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
325 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "limit of shadowmap side size - must be at least r_shadow_shadowmapping_bordersize+2"};
326 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "limit of shadowmap side size - can not be more than 1/8th of atlassize because lights store 6 sides (2x3 grid) and sometimes 12 sides (4x3 grid for shadows from EF_NOSELFSHADOW entities) and there are multiple lights..."};
327 cvar_t r_shadow_shadowmapping_texturesize = { CVAR_SAVE, "r_shadow_shadowmapping_texturesize", "8192", "size of shadowmap atlas texture - all shadowmaps are packed into this texture at frame start"};
328 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
329 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
330 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
331 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "5", "shadowmap size bias for filtering"};
332 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
333 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
334 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
335 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
336 cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
337 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
338 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
339 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect OpenGL 2.0 render path)"};
340 cvar_t r_shadow_culllights_pvs = {CVAR_SAVE, "r_shadow_culllights_pvs", "1", "check if light overlaps any visible bsp leafs when determining if the light is visible"};
341 cvar_t r_shadow_culllights_trace = {CVAR_SAVE, "r_shadow_culllights_trace", "1", "use raytraces from the eye to random places within light bounds to determine if the light is visible"};
342 cvar_t r_shadow_culllights_trace_eyejitter = {CVAR_SAVE, "r_shadow_culllights_trace_eyejitter", "16", "offset eye location randomly by this much"};
343 cvar_t r_shadow_culllights_trace_enlarge = {CVAR_SAVE, "r_shadow_culllights_trace_enlarge", "0", "make light bounds bigger by *(1.0+enlarge)"};
344 cvar_t r_shadow_culllights_trace_expand = {CVAR_SAVE, "r_shadow_culllights_trace_expand", "8", "make light bounds bigger by this many units"};
345 cvar_t r_shadow_culllights_trace_pad = {CVAR_SAVE, "r_shadow_culllights_trace_expand", "8", "accept traces that hit within this many units of the light bounds"};
346 cvar_t r_shadow_culllights_trace_samples = {CVAR_SAVE, "r_shadow_culllights_trace_samples", "16", "use this many traces to random positions (in addition to center trace)"};
347 cvar_t r_shadow_culllights_trace_tempsamples = {CVAR_SAVE, "r_shadow_culllights_trace_tempsamples", "16", "use this many traces if the light was created by csqc (no inter-frame caching), -1 disables the check (to avoid flicker entirely)"};
348 cvar_t r_shadow_culllights_trace_delay = {CVAR_SAVE, "r_shadow_culllights_trace_delay", "1", "light will be considered visible for this many seconds after any trace connects"};
349 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)"};
350 cvar_t r_shadow_bouncegrid_blur = {CVAR_SAVE, "r_shadow_bouncegrid_blur", "0", "apply a 1-radius blur on bouncegrid to denoise it and deal with boundary issues with surfaces"};
351 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"};
352 cvar_t r_shadow_bouncegrid_dynamic_bounceminimumintensity = { CVAR_SAVE, "r_shadow_bouncegrid_dynamic_bounceminimumintensity", "0.05", "stop bouncing once intensity drops below this fraction of the original particle color" };
353 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)"};
354 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"};
355 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"};
356 cvar_t r_shadow_bouncegrid_dynamic_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
357 cvar_t r_shadow_bouncegrid_dynamic_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_lightradiusscale", "2", "particles stop at this fraction of light radius (can be more than 1)"};
358 cvar_t r_shadow_bouncegrid_dynamic_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_maxbounce", "2", "maximum number of bounces for a particle (minimum is 0)"};
359 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"};
360 cvar_t r_shadow_bouncegrid_dynamic_quality = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_quality", "1", "amount of photons that should be fired (this is multiplied by spacing^2 to make it adaptive with spacing changes)"};
361 cvar_t r_shadow_bouncegrid_dynamic_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_spacing", "64", "unit size of bouncegrid pixel"};
362 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"};
363 cvar_t r_shadow_bouncegrid_dynamic_x = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_x", "64", "maximum texture size of bouncegrid on X axis"};
364 cvar_t r_shadow_bouncegrid_dynamic_y = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_y", "64", "maximum texture size of bouncegrid on Y axis"};
365 cvar_t r_shadow_bouncegrid_dynamic_z = {CVAR_SAVE, "r_shadow_bouncegrid_dynamic_z", "32", "maximum texture size of bouncegrid on Z axis"};
366 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"};
367 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)"};
368 cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
369 cvar_t r_shadow_bouncegrid_lightpathsize_conespread = {CVAR_SAVE, "r_shadow_bouncegrid_lightpathsize_conespread", "0.015625", "increase lightpathsize over distance at this rate per grid cell"};
370 cvar_t r_shadow_bouncegrid_lightpathsize_initial = {CVAR_SAVE, "r_shadow_bouncegrid_lightpathsize_initial", "0.5", "width (in grid cells) of the light path for accumulation of light in the bouncegrid texture"};
371 cvar_t r_shadow_bouncegrid_normalizevectors = { CVAR_SAVE, "r_shadow_bouncegrid_normalizevectors", "1", "normalize random vectors (otherwise their length can vary, which dims the lighting further from the light)" };
372 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"};
373 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "0.25", "brightness of particles contributing to bouncegrid texture"};
374 cvar_t r_shadow_bouncegrid_rng_seed = { CVAR_SAVE, "r_shadow_bouncegrid_rng_seed", "0", "0+ = use this number as RNG seed, -1 = use time instead for disco-like craziness in dynamic mode" };
375 cvar_t r_shadow_bouncegrid_rng_type = { CVAR_SAVE, "r_shadow_bouncegrid_rng_type", "0", "0 = Lehmer 128bit RNG (slow but high quality), 1 = lhcheeserand 32bit RNG (quick)" };
376 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"};
377 cvar_t r_shadow_bouncegrid_static = {CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
378 cvar_t r_shadow_bouncegrid_static_bounceminimumintensity = { CVAR_SAVE, "r_shadow_bouncegrid_static_bounceminimumintensity", "0.01", "stop bouncing once intensity drops below this fraction of the original particle color" };
379 cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
380 cvar_t r_shadow_bouncegrid_static_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_static_lightradiusscale", "2", "particles stop at this fraction of light radius (can be more than 1) when in static mode"};
381 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"};
382 cvar_t r_shadow_bouncegrid_static_maxphotons = {CVAR_SAVE, "r_shadow_bouncegrid_static_maxphotons", "250000", "upper bound on photons in static mode"};
383 cvar_t r_shadow_bouncegrid_static_quality = { CVAR_SAVE, "r_shadow_bouncegrid_static_quality", "16", "amount of photons that should be fired (this is multiplied by spacing^2 to make it adaptive with spacing changes)" };
384 cvar_t r_shadow_bouncegrid_static_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_static_spacing", "64", "unit size of bouncegrid pixel when in static mode"};
385 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
386 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"};
387 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!"};
388 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
389 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
390 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
391 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
392 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
393 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
394 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
395 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
396 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
397 cvar_t r_editlights_drawproperties = {0, "r_editlights_drawproperties", "1", "draw properties of currently selected light"};
398 cvar_t r_editlights_current_origin = {0, "r_editlights_current_origin", "0 0 0", "origin of selected light"};
399 cvar_t r_editlights_current_angles = {0, "r_editlights_current_angles", "0 0 0", "angles of selected light"};
400 cvar_t r_editlights_current_color = {0, "r_editlights_current_color", "1 1 1", "color of selected light"};
401 cvar_t r_editlights_current_radius = {0, "r_editlights_current_radius", "0", "radius of selected light"};
402 cvar_t r_editlights_current_corona = {0, "r_editlights_current_corona", "0", "corona intensity of selected light"};
403 cvar_t r_editlights_current_coronasize = {0, "r_editlights_current_coronasize", "0", "corona size of selected light"};
404 cvar_t r_editlights_current_style = {0, "r_editlights_current_style", "0", "style of selected light"};
405 cvar_t r_editlights_current_shadows = {0, "r_editlights_current_shadows", "0", "shadows flag of selected light"};
406 cvar_t r_editlights_current_cubemap = {0, "r_editlights_current_cubemap", "0", "cubemap of selected light"};
407 cvar_t r_editlights_current_ambient = {0, "r_editlights_current_ambient", "0", "ambient intensity of selected light"};
408 cvar_t r_editlights_current_diffuse = {0, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"};
409 cvar_t r_editlights_current_specular = {0, "r_editlights_current_specular", "1", "specular intensity of selected light"};
410 cvar_t r_editlights_current_normalmode = {0, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"};
411 cvar_t r_editlights_current_realtimemode = {0, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"};
413 r_shadow_bouncegrid_state_t r_shadow_bouncegrid_state;
415 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
416 #define ATTENTABLESIZE 256
417 // 1D gradient, 2D circle and 3D sphere attenuation textures
418 #define ATTEN1DSIZE 32
419 #define ATTEN2DSIZE 64
420 #define ATTEN3DSIZE 32
422 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
423 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
424 static float r_shadow_attentable[ATTENTABLESIZE+1];
426 rtlight_t *r_shadow_compilingrtlight;
427 static memexpandablearray_t r_shadow_worldlightsarray;
428 dlight_t *r_shadow_selectedlight;
429 dlight_t r_shadow_bufferlight;
430 vec3_t r_editlights_cursorlocation;
431 qboolean r_editlights_lockcursor;
433 extern int con_vislines;
435 void R_Shadow_UncompileWorldLights(void);
436 void R_Shadow_ClearWorldLights(void);
437 void R_Shadow_SaveWorldLights(void);
438 void R_Shadow_LoadWorldLights(void);
439 void R_Shadow_LoadLightsFile(void);
440 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
441 void R_Shadow_EditLights_Reload_f(void);
442 void R_Shadow_ValidateCvars(void);
443 static void R_Shadow_MakeTextures(void);
445 #define EDLIGHTSPRSIZE 8
446 skinframe_t *r_editlights_sprcursor;
447 skinframe_t *r_editlights_sprlight;
448 skinframe_t *r_editlights_sprnoshadowlight;
449 skinframe_t *r_editlights_sprcubemaplight;
450 skinframe_t *r_editlights_sprcubemapnoshadowlight;
451 skinframe_t *r_editlights_sprselection;
453 static void R_Shadow_DrawModelShadowMaps(void);
454 static void R_Shadow_MakeShadowMap(int texturesize);
455 static void R_Shadow_MakeVSDCT(void);
456 static void R_Shadow_SetShadowMode(void)
458 r_shadow_shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
459 r_shadow_shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
460 r_shadow_shadowmapmaxsize = bound(r_shadow_shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, r_shadow_shadowmaptexturesize / 8);
461 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
462 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
463 r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
464 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
465 r_shadow_shadowmapsampler = false;
466 r_shadow_shadowmappcf = 0;
467 r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
468 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
469 Mod_AllocLightmap_Init(&r_shadow_shadowmapatlas_state, r_main_mempool, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize);
470 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
472 switch(vid.renderpath)
474 case RENDERPATH_GL20:
475 if(r_shadow_shadowmapfilterquality < 0)
477 if (!r_fb.usedepthtextures)
478 r_shadow_shadowmappcf = 1;
479 else if((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && vid.support.arb_shadow && r_shadow_shadowmapshadowsampler)
481 r_shadow_shadowmapsampler = true;
482 r_shadow_shadowmappcf = 1;
484 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
485 r_shadow_shadowmappcf = 1;
486 else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa"))
487 r_shadow_shadowmappcf = 1;
489 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
493 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
494 switch (r_shadow_shadowmapfilterquality)
499 r_shadow_shadowmappcf = 1;
502 r_shadow_shadowmappcf = 1;
505 r_shadow_shadowmappcf = 2;
509 if (!r_fb.usedepthtextures)
510 r_shadow_shadowmapsampler = false;
511 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
513 case RENDERPATH_D3D9:
514 case RENDERPATH_D3D10:
515 case RENDERPATH_D3D11:
516 case RENDERPATH_SOFT:
517 r_shadow_shadowmapsampler = false;
518 r_shadow_shadowmappcf = 1;
519 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
521 case RENDERPATH_GL11:
522 case RENDERPATH_GL13:
523 case RENDERPATH_GLES1:
524 case RENDERPATH_GLES2:
529 if(R_CompileShader_CheckStaticParms())
533 qboolean R_Shadow_ShadowMappingEnabled(void)
535 switch (r_shadow_shadowmode)
537 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
544 static void R_Shadow_FreeShadowMaps(void)
546 Mod_AllocLightmap_Free(&r_shadow_shadowmapatlas_state);
548 R_Shadow_SetShadowMode();
550 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
554 if (r_shadow_shadowmap2ddepthtexture)
555 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
556 r_shadow_shadowmap2ddepthtexture = NULL;
558 if (r_shadow_shadowmap2ddepthbuffer)
559 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
560 r_shadow_shadowmap2ddepthbuffer = NULL;
562 if (r_shadow_shadowmapvsdcttexture)
563 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
564 r_shadow_shadowmapvsdcttexture = NULL;
567 static void r_shadow_start(void)
569 // allocate vertex processing arrays
570 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
571 r_shadow_attenuationgradienttexture = NULL;
572 r_shadow_attenuation2dtexture = NULL;
573 r_shadow_attenuation3dtexture = NULL;
574 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
575 r_shadow_shadowmap2ddepthtexture = NULL;
576 r_shadow_shadowmap2ddepthbuffer = NULL;
577 r_shadow_shadowmapvsdcttexture = NULL;
578 r_shadow_shadowmapmaxsize = 0;
579 r_shadow_shadowmaptexturesize = 0;
580 r_shadow_shadowmapfilterquality = -1;
581 r_shadow_shadowmapdepthbits = 0;
582 r_shadow_shadowmapvsdct = false;
583 r_shadow_shadowmapsampler = false;
584 r_shadow_shadowmappcf = 0;
587 R_Shadow_FreeShadowMaps();
589 r_shadow_texturepool = NULL;
590 r_shadow_filters_texturepool = NULL;
591 R_Shadow_ValidateCvars();
592 R_Shadow_MakeTextures();
593 r_shadow_scenemaxlights = 0;
594 r_shadow_scenenumlights = 0;
595 r_shadow_scenelightlist = NULL;
596 maxshadowtriangles = 0;
597 shadowelements = NULL;
598 maxshadowvertices = 0;
599 shadowvertex3f = NULL;
607 shadowmarklist = NULL;
612 shadowsideslist = NULL;
613 r_shadow_buffer_numleafpvsbytes = 0;
614 r_shadow_buffer_visitingleafpvs = NULL;
615 r_shadow_buffer_leafpvs = NULL;
616 r_shadow_buffer_leaflist = NULL;
617 r_shadow_buffer_numsurfacepvsbytes = 0;
618 r_shadow_buffer_surfacepvs = NULL;
619 r_shadow_buffer_surfacelist = NULL;
620 r_shadow_buffer_surfacesides = NULL;
621 r_shadow_buffer_numshadowtrispvsbytes = 0;
622 r_shadow_buffer_shadowtrispvs = NULL;
623 r_shadow_buffer_numlighttrispvsbytes = 0;
624 r_shadow_buffer_lighttrispvs = NULL;
626 r_shadow_usingdeferredprepass = false;
627 r_shadow_prepass_width = r_shadow_prepass_height = 0;
629 // determine renderpath specific capabilities, we don't need to figure
630 // these out per frame...
631 switch(vid.renderpath)
633 case RENDERPATH_GL20:
634 r_shadow_bouncegrid_state.allowdirectionalshading = true;
635 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
637 case RENDERPATH_GLES2:
638 // for performance reasons, do not use directional shading on GLES devices
639 r_shadow_bouncegrid_state.capable = vid.support.ext_texture_3d;
641 // these renderpaths do not currently have the code to display the bouncegrid, so disable it on them...
642 case RENDERPATH_GL11:
643 case RENDERPATH_GL13:
644 case RENDERPATH_GLES1:
645 case RENDERPATH_SOFT:
646 case RENDERPATH_D3D9:
647 case RENDERPATH_D3D10:
648 case RENDERPATH_D3D11:
653 static void R_Shadow_FreeDeferred(void);
654 static void r_shadow_shutdown(void)
657 R_Shadow_UncompileWorldLights();
659 R_Shadow_FreeShadowMaps();
661 r_shadow_usingdeferredprepass = false;
662 if (r_shadow_prepass_width)
663 R_Shadow_FreeDeferred();
664 r_shadow_prepass_width = r_shadow_prepass_height = 0;
667 r_shadow_scenemaxlights = 0;
668 r_shadow_scenenumlights = 0;
669 if (r_shadow_scenelightlist)
670 Mem_Free(r_shadow_scenelightlist);
671 r_shadow_scenelightlist = NULL;
672 r_shadow_bouncegrid_state.highpixels = NULL;
673 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
674 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
675 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
676 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
677 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
678 r_shadow_bouncegrid_state.maxsplatpaths = 0;
679 memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
680 r_shadow_attenuationgradienttexture = NULL;
681 r_shadow_attenuation2dtexture = NULL;
682 r_shadow_attenuation3dtexture = NULL;
683 R_FreeTexturePool(&r_shadow_texturepool);
684 R_FreeTexturePool(&r_shadow_filters_texturepool);
685 maxshadowtriangles = 0;
687 Mem_Free(shadowelements);
688 shadowelements = NULL;
690 Mem_Free(shadowvertex3f);
691 shadowvertex3f = NULL;
694 Mem_Free(vertexupdate);
697 Mem_Free(vertexremap);
703 Mem_Free(shadowmark);
706 Mem_Free(shadowmarklist);
707 shadowmarklist = NULL;
712 Mem_Free(shadowsides);
715 Mem_Free(shadowsideslist);
716 shadowsideslist = NULL;
717 r_shadow_buffer_numleafpvsbytes = 0;
718 if (r_shadow_buffer_visitingleafpvs)
719 Mem_Free(r_shadow_buffer_visitingleafpvs);
720 r_shadow_buffer_visitingleafpvs = NULL;
721 if (r_shadow_buffer_leafpvs)
722 Mem_Free(r_shadow_buffer_leafpvs);
723 r_shadow_buffer_leafpvs = NULL;
724 if (r_shadow_buffer_leaflist)
725 Mem_Free(r_shadow_buffer_leaflist);
726 r_shadow_buffer_leaflist = NULL;
727 r_shadow_buffer_numsurfacepvsbytes = 0;
728 if (r_shadow_buffer_surfacepvs)
729 Mem_Free(r_shadow_buffer_surfacepvs);
730 r_shadow_buffer_surfacepvs = NULL;
731 if (r_shadow_buffer_surfacelist)
732 Mem_Free(r_shadow_buffer_surfacelist);
733 r_shadow_buffer_surfacelist = NULL;
734 if (r_shadow_buffer_surfacesides)
735 Mem_Free(r_shadow_buffer_surfacesides);
736 r_shadow_buffer_surfacesides = NULL;
737 r_shadow_buffer_numshadowtrispvsbytes = 0;
738 if (r_shadow_buffer_shadowtrispvs)
739 Mem_Free(r_shadow_buffer_shadowtrispvs);
740 r_shadow_buffer_numlighttrispvsbytes = 0;
741 if (r_shadow_buffer_lighttrispvs)
742 Mem_Free(r_shadow_buffer_lighttrispvs);
745 static void r_shadow_newmap(void)
747 r_shadow_bouncegrid_state.highpixels = NULL;
748 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
749 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
750 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
751 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
752 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
753 r_shadow_bouncegrid_state.maxsplatpaths = 0;
754 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
755 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
756 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
757 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
758 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
759 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
760 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
761 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
762 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
763 R_Shadow_EditLights_Reload_f();
766 void R_Shadow_Init(void)
768 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
769 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
770 Cvar_RegisterVariable(&r_shadow_usebihculling);
771 Cvar_RegisterVariable(&r_shadow_usenormalmap);
772 Cvar_RegisterVariable(&r_shadow_debuglight);
773 Cvar_RegisterVariable(&r_shadow_deferred);
774 Cvar_RegisterVariable(&r_shadow_gloss);
775 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
776 Cvar_RegisterVariable(&r_shadow_glossintensity);
777 Cvar_RegisterVariable(&r_shadow_glossexponent);
778 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
779 Cvar_RegisterVariable(&r_shadow_glossexact);
780 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
781 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
782 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
783 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
784 Cvar_RegisterVariable(&r_shadow_projectdistance);
785 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
786 Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
787 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
788 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
789 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
790 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
791 Cvar_RegisterVariable(&r_shadow_realtime_world);
792 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
793 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
794 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
795 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
796 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
797 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
798 Cvar_RegisterVariable(&r_shadow_scissor);
799 Cvar_RegisterVariable(&r_shadow_shadowmapping);
800 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
801 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
802 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
803 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
804 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
805 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
806 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
807 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturesize);
808 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
809 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
810 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
811 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
812 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
813 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
814 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
815 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
816 Cvar_RegisterVariable(&r_shadow_polygonfactor);
817 Cvar_RegisterVariable(&r_shadow_polygonoffset);
818 Cvar_RegisterVariable(&r_shadow_texture3d);
819 Cvar_RegisterVariable(&r_shadow_culllights_pvs);
820 Cvar_RegisterVariable(&r_shadow_culllights_trace);
821 Cvar_RegisterVariable(&r_shadow_culllights_trace_eyejitter);
822 Cvar_RegisterVariable(&r_shadow_culllights_trace_enlarge);
823 Cvar_RegisterVariable(&r_shadow_culllights_trace_expand);
824 Cvar_RegisterVariable(&r_shadow_culllights_trace_pad);
825 Cvar_RegisterVariable(&r_shadow_culllights_trace_samples);
826 Cvar_RegisterVariable(&r_shadow_culllights_trace_tempsamples);
827 Cvar_RegisterVariable(&r_shadow_culllights_trace_delay);
828 Cvar_RegisterVariable(&r_shadow_bouncegrid);
829 Cvar_RegisterVariable(&r_shadow_bouncegrid_blur);
830 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
831 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_bounceminimumintensity);
832 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_culllightpaths);
833 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_directionalshading);
834 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_dlightparticlemultiplier);
835 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_hitmodels);
836 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_lightradiusscale);
837 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxbounce);
838 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxphotons);
839 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_quality);
840 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_spacing);
841 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_updateinterval);
842 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_x);
843 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_y);
844 Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_z);
845 Cvar_RegisterVariable(&r_shadow_bouncegrid_floatcolors);
846 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
847 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
848 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize_conespread);
849 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize_initial);
850 Cvar_RegisterVariable(&r_shadow_bouncegrid_normalizevectors);
851 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
852 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
853 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_seed);
854 Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_type);
855 Cvar_RegisterVariable(&r_shadow_bouncegrid_sortlightpaths);
856 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
857 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_bounceminimumintensity);
858 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
859 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
860 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
861 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxphotons);
862 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_quality);
863 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_spacing);
864 Cvar_RegisterVariable(&r_coronas);
865 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
866 Cvar_RegisterVariable(&r_coronas_occlusionquery);
867 Cvar_RegisterVariable(&gl_flashblend);
868 Cvar_RegisterVariable(&gl_ext_separatestencil);
869 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
870 R_Shadow_EditLights_Init();
871 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
872 r_shadow_scenemaxlights = 0;
873 r_shadow_scenenumlights = 0;
874 r_shadow_scenelightlist = NULL;
875 maxshadowtriangles = 0;
876 shadowelements = NULL;
877 maxshadowvertices = 0;
878 shadowvertex3f = NULL;
886 shadowmarklist = NULL;
891 shadowsideslist = NULL;
892 r_shadow_buffer_numleafpvsbytes = 0;
893 r_shadow_buffer_visitingleafpvs = NULL;
894 r_shadow_buffer_leafpvs = NULL;
895 r_shadow_buffer_leaflist = NULL;
896 r_shadow_buffer_numsurfacepvsbytes = 0;
897 r_shadow_buffer_surfacepvs = NULL;
898 r_shadow_buffer_surfacelist = NULL;
899 r_shadow_buffer_surfacesides = NULL;
900 r_shadow_buffer_shadowtrispvs = NULL;
901 r_shadow_buffer_lighttrispvs = NULL;
902 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
905 matrix4x4_t matrix_attenuationxyz =
908 {0.5, 0.0, 0.0, 0.5},
909 {0.0, 0.5, 0.0, 0.5},
910 {0.0, 0.0, 0.5, 0.5},
915 matrix4x4_t matrix_attenuationz =
918 {0.0, 0.0, 0.5, 0.5},
919 {0.0, 0.0, 0.0, 0.5},
920 {0.0, 0.0, 0.0, 0.5},
925 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
927 numvertices = ((numvertices + 255) & ~255) * vertscale;
928 numtriangles = ((numtriangles + 255) & ~255) * triscale;
929 // make sure shadowelements is big enough for this volume
930 if (maxshadowtriangles < numtriangles)
932 maxshadowtriangles = numtriangles;
934 Mem_Free(shadowelements);
935 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
937 // make sure shadowvertex3f is big enough for this volume
938 if (maxshadowvertices < numvertices)
940 maxshadowvertices = numvertices;
942 Mem_Free(shadowvertex3f);
943 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
947 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
949 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
950 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
951 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
952 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
953 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
955 if (r_shadow_buffer_visitingleafpvs)
956 Mem_Free(r_shadow_buffer_visitingleafpvs);
957 if (r_shadow_buffer_leafpvs)
958 Mem_Free(r_shadow_buffer_leafpvs);
959 if (r_shadow_buffer_leaflist)
960 Mem_Free(r_shadow_buffer_leaflist);
961 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
962 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
963 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
964 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
966 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
968 if (r_shadow_buffer_surfacepvs)
969 Mem_Free(r_shadow_buffer_surfacepvs);
970 if (r_shadow_buffer_surfacelist)
971 Mem_Free(r_shadow_buffer_surfacelist);
972 if (r_shadow_buffer_surfacesides)
973 Mem_Free(r_shadow_buffer_surfacesides);
974 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
975 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
976 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
977 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
979 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
981 if (r_shadow_buffer_shadowtrispvs)
982 Mem_Free(r_shadow_buffer_shadowtrispvs);
983 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
984 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
986 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
988 if (r_shadow_buffer_lighttrispvs)
989 Mem_Free(r_shadow_buffer_lighttrispvs);
990 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
991 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
995 void R_Shadow_PrepareShadowMark(int numtris)
997 // make sure shadowmark is big enough for this volume
998 if (maxshadowmark < numtris)
1000 maxshadowmark = numtris;
1002 Mem_Free(shadowmark);
1004 Mem_Free(shadowmarklist);
1005 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
1006 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
1007 shadowmarkcount = 0;
1010 // if shadowmarkcount wrapped we clear the array and adjust accordingly
1011 if (shadowmarkcount == 0)
1013 shadowmarkcount = 1;
1014 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
1019 void R_Shadow_PrepareShadowSides(int numtris)
1021 if (maxshadowsides < numtris)
1023 maxshadowsides = numtris;
1025 Mem_Free(shadowsides);
1026 if (shadowsideslist)
1027 Mem_Free(shadowsideslist);
1028 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
1029 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
1034 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)
1037 int outtriangles = 0, outvertices = 0;
1039 const float *vertex;
1040 float ratio, direction[3], projectvector[3];
1042 if (projectdirection)
1043 VectorScale(projectdirection, projectdistance, projectvector);
1045 VectorClear(projectvector);
1047 // create the vertices
1048 if (projectdirection)
1050 for (i = 0;i < numshadowmarktris;i++)
1052 element = inelement3i + shadowmarktris[i] * 3;
1053 for (j = 0;j < 3;j++)
1055 if (vertexupdate[element[j]] != vertexupdatenum)
1057 vertexupdate[element[j]] = vertexupdatenum;
1058 vertexremap[element[j]] = outvertices;
1059 vertex = invertex3f + element[j] * 3;
1060 // project one copy of the vertex according to projectvector
1061 VectorCopy(vertex, outvertex3f);
1062 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1071 for (i = 0;i < numshadowmarktris;i++)
1073 element = inelement3i + shadowmarktris[i] * 3;
1074 for (j = 0;j < 3;j++)
1076 if (vertexupdate[element[j]] != vertexupdatenum)
1078 vertexupdate[element[j]] = vertexupdatenum;
1079 vertexremap[element[j]] = outvertices;
1080 vertex = invertex3f + element[j] * 3;
1081 // project one copy of the vertex to the sphere radius of the light
1082 // (FIXME: would projecting it to the light box be better?)
1083 VectorSubtract(vertex, projectorigin, direction);
1084 ratio = projectdistance / VectorLength(direction);
1085 VectorCopy(vertex, outvertex3f);
1086 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1094 if (r_shadow_frontsidecasting.integer)
1096 for (i = 0;i < numshadowmarktris;i++)
1098 int remappedelement[3];
1100 const int *neighbortriangle;
1102 markindex = shadowmarktris[i] * 3;
1103 element = inelement3i + markindex;
1104 neighbortriangle = inneighbor3i + markindex;
1105 // output the front and back triangles
1106 outelement3i[0] = vertexremap[element[0]];
1107 outelement3i[1] = vertexremap[element[1]];
1108 outelement3i[2] = vertexremap[element[2]];
1109 outelement3i[3] = vertexremap[element[2]] + 1;
1110 outelement3i[4] = vertexremap[element[1]] + 1;
1111 outelement3i[5] = vertexremap[element[0]] + 1;
1115 // output the sides (facing outward from this triangle)
1116 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1118 remappedelement[0] = vertexremap[element[0]];
1119 remappedelement[1] = vertexremap[element[1]];
1120 outelement3i[0] = remappedelement[1];
1121 outelement3i[1] = remappedelement[0];
1122 outelement3i[2] = remappedelement[0] + 1;
1123 outelement3i[3] = remappedelement[1];
1124 outelement3i[4] = remappedelement[0] + 1;
1125 outelement3i[5] = remappedelement[1] + 1;
1130 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1132 remappedelement[1] = vertexremap[element[1]];
1133 remappedelement[2] = vertexremap[element[2]];
1134 outelement3i[0] = remappedelement[2];
1135 outelement3i[1] = remappedelement[1];
1136 outelement3i[2] = remappedelement[1] + 1;
1137 outelement3i[3] = remappedelement[2];
1138 outelement3i[4] = remappedelement[1] + 1;
1139 outelement3i[5] = remappedelement[2] + 1;
1144 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1146 remappedelement[0] = vertexremap[element[0]];
1147 remappedelement[2] = vertexremap[element[2]];
1148 outelement3i[0] = remappedelement[0];
1149 outelement3i[1] = remappedelement[2];
1150 outelement3i[2] = remappedelement[2] + 1;
1151 outelement3i[3] = remappedelement[0];
1152 outelement3i[4] = remappedelement[2] + 1;
1153 outelement3i[5] = remappedelement[0] + 1;
1162 for (i = 0;i < numshadowmarktris;i++)
1164 int remappedelement[3];
1166 const int *neighbortriangle;
1168 markindex = shadowmarktris[i] * 3;
1169 element = inelement3i + markindex;
1170 neighbortriangle = inneighbor3i + markindex;
1171 // output the front and back triangles
1172 outelement3i[0] = vertexremap[element[2]];
1173 outelement3i[1] = vertexremap[element[1]];
1174 outelement3i[2] = vertexremap[element[0]];
1175 outelement3i[3] = vertexremap[element[0]] + 1;
1176 outelement3i[4] = vertexremap[element[1]] + 1;
1177 outelement3i[5] = vertexremap[element[2]] + 1;
1181 // output the sides (facing outward from this triangle)
1182 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1184 remappedelement[0] = vertexremap[element[0]];
1185 remappedelement[1] = vertexremap[element[1]];
1186 outelement3i[0] = remappedelement[0];
1187 outelement3i[1] = remappedelement[1];
1188 outelement3i[2] = remappedelement[1] + 1;
1189 outelement3i[3] = remappedelement[0];
1190 outelement3i[4] = remappedelement[1] + 1;
1191 outelement3i[5] = remappedelement[0] + 1;
1196 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1198 remappedelement[1] = vertexremap[element[1]];
1199 remappedelement[2] = vertexremap[element[2]];
1200 outelement3i[0] = remappedelement[1];
1201 outelement3i[1] = remappedelement[2];
1202 outelement3i[2] = remappedelement[2] + 1;
1203 outelement3i[3] = remappedelement[1];
1204 outelement3i[4] = remappedelement[2] + 1;
1205 outelement3i[5] = remappedelement[1] + 1;
1210 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1212 remappedelement[0] = vertexremap[element[0]];
1213 remappedelement[2] = vertexremap[element[2]];
1214 outelement3i[0] = remappedelement[2];
1215 outelement3i[1] = remappedelement[0];
1216 outelement3i[2] = remappedelement[0] + 1;
1217 outelement3i[3] = remappedelement[2];
1218 outelement3i[4] = remappedelement[0] + 1;
1219 outelement3i[5] = remappedelement[2] + 1;
1227 *outnumvertices = outvertices;
1228 return outtriangles;
1231 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)
1234 int outtriangles = 0, outvertices = 0;
1236 const float *vertex;
1237 float ratio, direction[3], projectvector[3];
1240 if (projectdirection)
1241 VectorScale(projectdirection, projectdistance, projectvector);
1243 VectorClear(projectvector);
1245 for (i = 0;i < numshadowmarktris;i++)
1247 int remappedelement[3];
1249 const int *neighbortriangle;
1251 markindex = shadowmarktris[i] * 3;
1252 neighbortriangle = inneighbor3i + markindex;
1253 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1254 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1255 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1256 if (side[0] + side[1] + side[2] == 0)
1260 element = inelement3i + markindex;
1262 // create the vertices
1263 for (j = 0;j < 3;j++)
1265 if (side[j] + side[j+1] == 0)
1268 if (vertexupdate[k] != vertexupdatenum)
1270 vertexupdate[k] = vertexupdatenum;
1271 vertexremap[k] = outvertices;
1272 vertex = invertex3f + k * 3;
1273 VectorCopy(vertex, outvertex3f);
1274 if (projectdirection)
1276 // project one copy of the vertex according to projectvector
1277 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1281 // project one copy of the vertex to the sphere radius of the light
1282 // (FIXME: would projecting it to the light box be better?)
1283 VectorSubtract(vertex, projectorigin, direction);
1284 ratio = projectdistance / VectorLength(direction);
1285 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1292 // output the sides (facing outward from this triangle)
1295 remappedelement[0] = vertexremap[element[0]];
1296 remappedelement[1] = vertexremap[element[1]];
1297 outelement3i[0] = remappedelement[1];
1298 outelement3i[1] = remappedelement[0];
1299 outelement3i[2] = remappedelement[0] + 1;
1300 outelement3i[3] = remappedelement[1];
1301 outelement3i[4] = remappedelement[0] + 1;
1302 outelement3i[5] = remappedelement[1] + 1;
1309 remappedelement[1] = vertexremap[element[1]];
1310 remappedelement[2] = vertexremap[element[2]];
1311 outelement3i[0] = remappedelement[2];
1312 outelement3i[1] = remappedelement[1];
1313 outelement3i[2] = remappedelement[1] + 1;
1314 outelement3i[3] = remappedelement[2];
1315 outelement3i[4] = remappedelement[1] + 1;
1316 outelement3i[5] = remappedelement[2] + 1;
1323 remappedelement[0] = vertexremap[element[0]];
1324 remappedelement[2] = vertexremap[element[2]];
1325 outelement3i[0] = remappedelement[0];
1326 outelement3i[1] = remappedelement[2];
1327 outelement3i[2] = remappedelement[2] + 1;
1328 outelement3i[3] = remappedelement[0];
1329 outelement3i[4] = remappedelement[2] + 1;
1330 outelement3i[5] = remappedelement[0] + 1;
1337 *outnumvertices = outvertices;
1338 return outtriangles;
1341 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)
1347 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1349 tend = firsttriangle + numtris;
1350 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1352 // surface box entirely inside light box, no box cull
1353 if (projectdirection)
1355 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1357 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1358 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1359 shadowmarklist[numshadowmark++] = t;
1364 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1365 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1366 shadowmarklist[numshadowmark++] = t;
1371 // surface box not entirely inside light box, cull each triangle
1372 if (projectdirection)
1374 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1376 v[0] = invertex3f + e[0] * 3;
1377 v[1] = invertex3f + e[1] * 3;
1378 v[2] = invertex3f + e[2] * 3;
1379 TriangleNormal(v[0], v[1], v[2], normal);
1380 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1381 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1382 shadowmarklist[numshadowmark++] = t;
1387 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1389 v[0] = invertex3f + e[0] * 3;
1390 v[1] = invertex3f + e[1] * 3;
1391 v[2] = invertex3f + e[2] * 3;
1392 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1393 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1394 shadowmarklist[numshadowmark++] = t;
1400 static qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1405 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1407 // check if the shadow volume intersects the near plane
1409 // a ray between the eye and light origin may intersect the caster,
1410 // indicating that the shadow may touch the eye location, however we must
1411 // test the near plane (a polygon), not merely the eye location, so it is
1412 // easiest to enlarge the caster bounding shape slightly for this.
1418 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)
1420 int i, tris, outverts;
1421 if (projectdistance < 0.1)
1423 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1426 if (!numverts || !nummarktris)
1428 // make sure shadowelements is big enough for this volume
1429 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1430 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1432 if (maxvertexupdate < numverts)
1434 maxvertexupdate = numverts;
1436 Mem_Free(vertexupdate);
1438 Mem_Free(vertexremap);
1439 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1440 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1441 vertexupdatenum = 0;
1444 if (vertexupdatenum == 0)
1446 vertexupdatenum = 1;
1447 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1448 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1451 for (i = 0;i < nummarktris;i++)
1452 shadowmark[marktris[i]] = shadowmarkcount;
1454 if (r_shadow_compilingrtlight)
1456 // if we're compiling an rtlight, capture the mesh
1457 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1458 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1459 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1460 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1462 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1464 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1465 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1466 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1470 // decide which type of shadow to generate and set stencil mode
1471 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1472 // generate the sides or a solid volume, depending on type
1473 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1474 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1476 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1477 r_refdef.stats[r_stat_lights_dynamicshadowtriangles] += tris;
1478 r_refdef.stats[r_stat_lights_shadowtriangles] += tris;
1479 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1481 // increment stencil if frontface is infront of depthbuffer
1482 GL_CullFace(r_refdef.view.cullface_front);
1483 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1484 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1485 // decrement stencil if backface is infront of depthbuffer
1486 GL_CullFace(r_refdef.view.cullface_back);
1487 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1489 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1491 // decrement stencil if backface is behind depthbuffer
1492 GL_CullFace(r_refdef.view.cullface_front);
1493 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1494 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1495 // increment stencil if frontface is behind depthbuffer
1496 GL_CullFace(r_refdef.view.cullface_back);
1497 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1499 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1500 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1504 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1506 // p1, p2, p3 are in the cubemap's local coordinate system
1507 // bias = border/(size - border)
1510 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1511 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1512 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1513 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1515 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1516 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1517 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1518 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1520 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1521 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1522 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1524 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1525 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1526 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1527 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1529 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1530 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1531 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1532 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1534 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1535 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1536 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1538 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1539 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1540 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1541 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1543 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1544 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1545 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1546 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1548 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1549 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1550 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1555 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1557 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1558 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1561 VectorSubtract(maxs, mins, radius);
1562 VectorScale(radius, 0.5f, radius);
1563 VectorAdd(mins, radius, center);
1564 Matrix4x4_Transform(worldtolight, center, lightcenter);
1565 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1566 VectorSubtract(lightcenter, lightradius, pmin);
1567 VectorAdd(lightcenter, lightradius, pmax);
1569 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1570 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1571 if(ap1 > bias*an1 && ap2 > bias*an2)
1573 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1574 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1575 if(an1 > bias*ap1 && an2 > bias*ap2)
1577 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1578 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1580 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1581 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1582 if(ap1 > bias*an1 && ap2 > bias*an2)
1584 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1585 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1586 if(an1 > bias*ap1 && an2 > bias*ap2)
1588 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1589 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1591 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1592 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1593 if(ap1 > bias*an1 && ap2 > bias*an2)
1595 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1596 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1597 if(an1 > bias*ap1 && an2 > bias*ap2)
1599 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1600 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1605 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1607 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1609 // p is in the cubemap's local coordinate system
1610 // bias = border/(size - border)
1611 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1612 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1613 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1615 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1616 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1617 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1618 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1619 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1620 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1624 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1628 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1629 float scale = (size - 2*border)/size, len;
1630 float bias = border / (float)(size - border), dp, dn, ap, an;
1631 // check if cone enclosing side would cross frustum plane
1632 scale = 2 / (scale*scale + 2);
1633 Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
1634 for (i = 0;i < 5;i++)
1636 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
1638 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1639 len = scale*VectorLength2(n);
1640 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1641 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1642 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1644 if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1646 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1647 len = scale*VectorLength2(n);
1648 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1649 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1650 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1652 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1653 // check if frustum corners/origin cross plane sides
1655 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1656 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1657 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1658 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1659 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1660 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1661 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1662 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1663 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1664 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1665 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1666 for (i = 0;i < 4;i++)
1668 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1669 VectorSubtract(n, p, n);
1670 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1671 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1672 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1673 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1674 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1675 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1676 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1677 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1678 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1681 // finite version, assumes corners are a finite distance from origin dependent on far plane
1682 for (i = 0;i < 5;i++)
1684 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1685 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1686 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1687 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1688 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1689 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1690 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1691 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1692 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1693 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1696 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1699 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)
1707 int mask, surfacemask = 0;
1708 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1710 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1711 tend = firsttriangle + numtris;
1712 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1714 // surface box entirely inside light box, no box cull
1715 if (projectdirection)
1717 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1719 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1720 TriangleNormal(v[0], v[1], v[2], normal);
1721 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
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]))
1742 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1743 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1744 surfacemask |= mask;
1747 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;
1748 shadowsides[numshadowsides] = mask;
1749 shadowsideslist[numshadowsides++] = t;
1757 // surface box not entirely inside light box, cull each triangle
1758 if (projectdirection)
1760 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1762 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1763 TriangleNormal(v[0], v[1], v[2], normal);
1764 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1765 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1767 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1768 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1769 surfacemask |= mask;
1772 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;
1773 shadowsides[numshadowsides] = mask;
1774 shadowsideslist[numshadowsides++] = t;
1781 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1783 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1784 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1785 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1787 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1788 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1789 surfacemask |= mask;
1792 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;
1793 shadowsides[numshadowsides] = mask;
1794 shadowsideslist[numshadowsides++] = t;
1803 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)
1805 int i, j, outtriangles = 0;
1806 int *outelement3i[6];
1807 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1809 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1810 // make sure shadowelements is big enough for this mesh
1811 if (maxshadowtriangles < outtriangles)
1812 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1814 // compute the offset and size of the separate index lists for each cubemap side
1816 for (i = 0;i < 6;i++)
1818 outelement3i[i] = shadowelements + outtriangles * 3;
1819 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1820 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1821 outtriangles += sidetotals[i];
1824 // gather up the (sparse) triangles into separate index lists for each cubemap side
1825 for (i = 0;i < numsidetris;i++)
1827 const int *element = elements + sidetris[i] * 3;
1828 for (j = 0;j < 6;j++)
1830 if (sides[i] & (1 << j))
1832 outelement3i[j][0] = element[0];
1833 outelement3i[j][1] = element[1];
1834 outelement3i[j][2] = element[2];
1835 outelement3i[j] += 3;
1840 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1843 static void R_Shadow_MakeTextures_MakeCorona(void)
1847 unsigned char pixels[32][32][4];
1848 for (y = 0;y < 32;y++)
1850 dy = (y - 15.5f) * (1.0f / 16.0f);
1851 for (x = 0;x < 32;x++)
1853 dx = (x - 15.5f) * (1.0f / 16.0f);
1854 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1855 a = bound(0, a, 255);
1856 pixels[y][x][0] = a;
1857 pixels[y][x][1] = a;
1858 pixels[y][x][2] = a;
1859 pixels[y][x][3] = 255;
1862 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, false);
1865 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1867 float dist = sqrt(x*x+y*y+z*z);
1868 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1869 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1870 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1873 static void R_Shadow_MakeTextures(void)
1876 float intensity, dist;
1878 R_Shadow_FreeShadowMaps();
1879 R_FreeTexturePool(&r_shadow_texturepool);
1880 r_shadow_texturepool = R_AllocTexturePool();
1881 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1882 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1883 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1884 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1885 for (x = 0;x <= ATTENTABLESIZE;x++)
1887 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1888 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1889 r_shadow_attentable[x] = bound(0, intensity, 1);
1891 // 1D gradient texture
1892 for (x = 0;x < ATTEN1DSIZE;x++)
1893 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1894 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1895 // 2D circle texture
1896 for (y = 0;y < ATTEN2DSIZE;y++)
1897 for (x = 0;x < ATTEN2DSIZE;x++)
1898 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);
1899 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1900 // 3D sphere texture
1901 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1903 for (z = 0;z < ATTEN3DSIZE;z++)
1904 for (y = 0;y < ATTEN3DSIZE;y++)
1905 for (x = 0;x < ATTEN3DSIZE;x++)
1906 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));
1907 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);
1910 r_shadow_attenuation3dtexture = NULL;
1913 R_Shadow_MakeTextures_MakeCorona();
1915 // Editor light sprites
1916 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1933 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1934 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1951 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1952 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1969 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1970 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1987 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1988 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
2005 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
2006 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
2023 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
2026 void R_Shadow_ValidateCvars(void)
2028 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
2029 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
2030 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
2031 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
2032 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
2033 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
2036 void R_Shadow_RenderMode_Begin(void)
2042 R_Shadow_ValidateCvars();
2044 if (!r_shadow_attenuation2dtexture
2045 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
2046 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
2047 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
2048 R_Shadow_MakeTextures();
2051 R_Mesh_ResetTextureState();
2052 GL_BlendFunc(GL_ONE, GL_ZERO);
2053 GL_DepthRange(0, 1);
2054 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
2056 GL_DepthMask(false);
2057 GL_Color(0, 0, 0, 1);
2058 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2060 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2062 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
2064 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
2065 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
2067 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
2069 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
2070 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
2074 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
2075 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
2078 switch(vid.renderpath)
2080 case RENDERPATH_GL20:
2081 case RENDERPATH_D3D9:
2082 case RENDERPATH_D3D10:
2083 case RENDERPATH_D3D11:
2084 case RENDERPATH_SOFT:
2085 case RENDERPATH_GLES2:
2086 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
2088 case RENDERPATH_GL11:
2089 case RENDERPATH_GL13:
2090 case RENDERPATH_GLES1:
2091 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
2092 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
2093 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
2094 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
2095 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
2096 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
2098 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
2104 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
2105 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
2106 r_shadow_drawbuffer = drawbuffer;
2107 r_shadow_readbuffer = readbuffer;
2109 r_shadow_cullface_front = r_refdef.view.cullface_front;
2110 r_shadow_cullface_back = r_refdef.view.cullface_back;
2113 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
2115 rsurface.rtlight = rtlight;
2118 void R_Shadow_RenderMode_Reset(void)
2120 R_Mesh_ResetTextureState();
2121 R_Mesh_SetRenderTargets(r_shadow_viewfbo, r_shadow_viewdepthtexture, r_shadow_viewcolortexture, NULL, NULL, NULL);
2122 R_SetViewport(&r_refdef.view.viewport);
2123 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
2124 GL_DepthRange(0, 1);
2126 GL_DepthMask(false);
2127 GL_DepthFunc(GL_LEQUAL);
2128 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2129 r_refdef.view.cullface_front = r_shadow_cullface_front;
2130 r_refdef.view.cullface_back = r_shadow_cullface_back;
2131 GL_CullFace(r_refdef.view.cullface_back);
2132 GL_Color(1, 1, 1, 1);
2133 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2134 GL_BlendFunc(GL_ONE, GL_ZERO);
2135 R_SetupShader_Generic_NoTexture(false, false);
2136 r_shadow_usingshadowmap2d = false;
2137 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2140 void R_Shadow_ClearStencil(void)
2142 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2143 r_refdef.stats[r_stat_lights_clears]++;
2146 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2148 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2149 if (r_shadow_rendermode == mode)
2151 R_Shadow_RenderMode_Reset();
2152 GL_DepthFunc(GL_LESS);
2153 GL_ColorMask(0, 0, 0, 0);
2154 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2155 GL_CullFace(GL_NONE);
2156 R_SetupShader_DepthOrShadow(false, false, false); // FIXME test if we have a skeletal model?
2157 r_shadow_rendermode = mode;
2162 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2163 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2164 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2166 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2167 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2168 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2173 static void R_Shadow_MakeVSDCT(void)
2175 // maps to a 2x3 texture rectangle with normalized coordinates
2180 // stores abs(dir.xy), offset.xy/2.5
2181 unsigned char data[4*6] =
2183 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2184 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2185 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2186 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2187 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2188 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2190 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2193 static void R_Shadow_MakeShadowMap(int texturesize)
2195 switch (r_shadow_shadowmode)
2197 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2198 if (r_shadow_shadowmap2ddepthtexture) return;
2199 if (r_fb.usedepthtextures)
2201 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);
2202 r_shadow_shadowmap2ddepthbuffer = NULL;
2203 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2207 r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", texturesize, texturesize, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2208 r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
2209 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2217 void R_Shadow_ClearShadowMapTexture(void)
2219 r_viewport_t viewport;
2220 float clearcolor[4];
2222 // if they don't exist, create our textures now
2223 if (!r_shadow_shadowmap2ddepthtexture)
2224 R_Shadow_MakeShadowMap(r_shadow_shadowmaptexturesize);
2225 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2226 R_Shadow_MakeVSDCT();
2228 // we're setting up to render shadowmaps, so change rendermode
2229 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2231 R_Mesh_ResetTextureState();
2232 R_Shadow_RenderMode_Reset();
2233 if (r_shadow_shadowmap2ddepthbuffer)
2234 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2236 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2237 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2238 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2242 // we have to set a viewport to clear anything in some renderpaths (D3D)
2243 R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize, 0, 0, 1.0, 1.0, 0.001f, 1.0f, NULL);
2244 R_SetViewport(&viewport);
2245 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2246 if (r_shadow_shadowmap2ddepthbuffer)
2247 GL_ColorMask(1, 1, 1, 1);
2249 GL_ColorMask(0, 0, 0, 0);
2250 switch (vid.renderpath)
2252 case RENDERPATH_GL11:
2253 case RENDERPATH_GL13:
2254 case RENDERPATH_GL20:
2255 case RENDERPATH_SOFT:
2256 case RENDERPATH_GLES1:
2257 case RENDERPATH_GLES2:
2258 GL_CullFace(r_refdef.view.cullface_back);
2260 case RENDERPATH_D3D9:
2261 case RENDERPATH_D3D10:
2262 case RENDERPATH_D3D11:
2263 // we invert the cull mode because we flip the projection matrix
2264 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2265 GL_CullFace(r_refdef.view.cullface_front);
2268 Vector4Set(clearcolor, 1, 1, 1, 1);
2269 if (r_shadow_shadowmap2ddepthbuffer)
2270 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2272 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2275 static void R_Shadow_SetShadowmapParametersForLight(qboolean noselfshadowpass)
2277 int size = rsurface.rtlight->shadowmapatlassidesize;
2278 float nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2279 float farclip = 1.0f;
2280 float bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2281 r_shadow_lightshadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
2282 r_shadow_lightshadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
2283 r_shadow_lightshadowmap_texturescale[2] = rsurface.rtlight->shadowmapatlasposition[0] + (noselfshadowpass ? size * 2 : 0);
2284 r_shadow_lightshadowmap_texturescale[3] = rsurface.rtlight->shadowmapatlasposition[1];
2285 r_shadow_lightshadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2286 r_shadow_lightshadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2287 r_shadow_lightshadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2288 r_shadow_lightshadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2289 if (r_shadow_shadowmap2ddepthbuffer)
2291 // completely different meaning than in depthtexture approach
2292 r_shadow_lightshadowmap_parameters[1] = 0;
2293 r_shadow_lightshadowmap_parameters[3] = -bias;
2297 static void R_Shadow_RenderMode_ShadowMap(int side, int size, int x, int y)
2299 float nearclip, farclip, bias;
2300 r_viewport_t viewport;
2302 float clearcolor[4];
2304 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_SHADOWMAP2D)
2306 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2308 R_Mesh_ResetTextureState();
2309 R_Shadow_RenderMode_Reset();
2310 if (r_shadow_shadowmap2ddepthbuffer)
2311 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2313 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2314 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2315 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2320 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2322 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2324 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
2325 R_SetViewport(&viewport);
2326 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2327 flipped = (side & 1) ^ (side >> 2);
2328 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2329 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2331 Vector4Set(clearcolor, 1,1,1,1);
2332 if (r_shadow_shadowmap2ddepthbuffer)
2333 GL_ColorMask(1,1,1,1);
2335 GL_ColorMask(0,0,0,0);
2336 switch(vid.renderpath)
2338 case RENDERPATH_GL11:
2339 case RENDERPATH_GL13:
2340 case RENDERPATH_GL20:
2341 case RENDERPATH_SOFT:
2342 case RENDERPATH_GLES1:
2343 case RENDERPATH_GLES2:
2344 GL_CullFace(r_refdef.view.cullface_back);
2346 case RENDERPATH_D3D9:
2347 case RENDERPATH_D3D10:
2348 case RENDERPATH_D3D11:
2349 // we invert the cull mode because we flip the projection matrix
2350 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2351 GL_CullFace(r_refdef.view.cullface_front);
2355 // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
2356 r_shadow_shadowmapside = side;
2359 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass)
2361 R_Mesh_ResetTextureState();
2364 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2365 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2366 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2367 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2370 R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
2371 R_Shadow_RenderMode_Reset();
2372 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2374 GL_DepthFunc(GL_EQUAL);
2375 // do global setup needed for the chosen lighting mode
2376 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2377 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2378 r_shadow_usingshadowmap2d = shadowmapping;
2379 r_shadow_rendermode = r_shadow_lightingrendermode;
2380 // only draw light where this geometry was already rendered AND the
2381 // stencil is 128 (values other than this mean shadow)
2383 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2385 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2388 static const unsigned short bboxelements[36] =
2398 static const float bboxpoints[8][3] =
2410 void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping)
2413 float vertex3f[8*3];
2414 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2415 // do global setup needed for the chosen lighting mode
2416 R_Shadow_RenderMode_Reset();
2417 r_shadow_rendermode = r_shadow_lightingrendermode;
2418 R_EntityMatrix(&identitymatrix);
2419 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2420 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2421 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
2422 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2424 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
2426 r_shadow_usingshadowmap2d = shadowmapping;
2428 // render the lighting
2429 R_SetupShader_DeferredLight(rsurface.rtlight);
2430 for (i = 0;i < 8;i++)
2431 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2432 GL_ColorMask(1,1,1,1);
2433 GL_DepthMask(false);
2434 GL_DepthRange(0, 1);
2435 GL_PolygonOffset(0, 0);
2437 GL_DepthFunc(GL_GREATER);
2438 GL_CullFace(r_refdef.view.cullface_back);
2439 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
2440 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2443 #define MAXBOUNCEGRIDSPLATSIZE 7
2444 #define MAXBOUNCEGRIDSPLATSIZE1 (MAXBOUNCEGRIDSPLATSIZE+1)
2446 // these are temporary data per-frame, sorted and performed in a more
2447 // cache-friendly order than the original photons
2448 typedef struct r_shadow_bouncegrid_splatpath_s
2454 vec_t splatintensity;
2455 vec_t splatsize_current;
2456 vec_t splatsize_perstep;
2457 int remainingsplats;
2459 r_shadow_bouncegrid_splatpath_t;
2461 static void R_Shadow_BounceGrid_AddSplatPath(vec3_t originalstart, vec3_t originalend, vec3_t color, vec_t distancetraveled)
2471 r_shadow_bouncegrid_splatpath_t *path;
2473 // cull paths that fail R_CullBox in dynamic mode
2474 if (!r_shadow_bouncegrid_state.settings.staticmode
2475 && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
2477 vec3_t cullmins, cullmaxs;
2478 cullmins[0] = min(originalstart[0], originalend[0]) - r_shadow_bouncegrid_state.settings.spacing[0];
2479 cullmins[1] = min(originalstart[1], originalend[1]) - r_shadow_bouncegrid_state.settings.spacing[1];
2480 cullmins[2] = min(originalstart[2], originalend[2]) - r_shadow_bouncegrid_state.settings.spacing[2];
2481 cullmaxs[0] = max(originalstart[0], originalend[0]) + r_shadow_bouncegrid_state.settings.spacing[0];
2482 cullmaxs[1] = max(originalstart[1], originalend[1]) + r_shadow_bouncegrid_state.settings.spacing[1];
2483 cullmaxs[2] = max(originalstart[2], originalend[2]) + r_shadow_bouncegrid_state.settings.spacing[2];
2484 if (R_CullBox(cullmins, cullmaxs))
2488 // if the light path is going upward, reverse it - we always draw down.
2489 if (originalend[2] < originalstart[2])
2491 VectorCopy(originalend, start);
2492 VectorCopy(originalstart, end);
2496 VectorCopy(originalstart, start);
2497 VectorCopy(originalend, end);
2500 // transform to texture pixels
2501 start[0] = (start[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2502 start[1] = (start[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2503 start[2] = (start[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2504 end[0] = (end[0] - r_shadow_bouncegrid_state.mins[0]) * r_shadow_bouncegrid_state.ispacing[0];
2505 end[1] = (end[1] - r_shadow_bouncegrid_state.mins[1]) * r_shadow_bouncegrid_state.ispacing[1];
2506 end[2] = (end[2] - r_shadow_bouncegrid_state.mins[2]) * r_shadow_bouncegrid_state.ispacing[2];
2508 // check if we need to grow the splatpaths array
2509 if (r_shadow_bouncegrid_state.maxsplatpaths <= r_shadow_bouncegrid_state.numsplatpaths)
2511 // double the limit, this will persist from frame to frame so we don't
2512 // make the same mistake each time
2513 r_shadow_bouncegrid_state.maxsplatpaths *= 2;
2514 if (r_shadow_bouncegrid_state.maxsplatpaths < 16384)
2515 r_shadow_bouncegrid_state.maxsplatpaths = 16384;
2516 r_shadow_bouncegrid_state.splatpaths = (r_shadow_bouncegrid_splatpath_t *)Mem_Realloc(r_main_mempool, r_shadow_bouncegrid_state.splatpaths, sizeof(r_shadow_bouncegrid_splatpath_t) * r_shadow_bouncegrid_state.maxsplatpaths);
2519 // divide a series of splats along the length using the maximum axis
2520 VectorSubtract(end, start, diff);
2521 // pick the best axis to trace along
2523 if (diff[1]*diff[1] > diff[bestaxis]*diff[bestaxis])
2525 if (diff[2]*diff[2] > diff[bestaxis]*diff[bestaxis])
2527 len = fabs(diff[bestaxis]);
2529 numsplats = (int)(floor(len + 0.5f));
2531 numsplats = bound(0, numsplats, 1024);
2533 VectorSubtract(originalstart, originalend, originaldir);
2534 VectorNormalize(originaldir);
2536 path = r_shadow_bouncegrid_state.splatpaths + r_shadow_bouncegrid_state.numsplatpaths++;
2537 VectorCopy(start, path->point);
2538 VectorScale(diff, ilen, path->step);
2539 VectorCopy(color, path->splatcolor);
2540 VectorCopy(originaldir, path->splatdir);
2541 path->splatsize_current = r_shadow_bouncegrid_state.settings.lightpathsize_initial + r_shadow_bouncegrid_state.settings.lightpathsize_conespread * distancetraveled * r_shadow_bouncegrid_state.ispacing[0];
2542 path->splatsize_perstep = r_shadow_bouncegrid_state.settings.lightpathsize_conespread;
2543 path->splatintensity = VectorLength(color);
2544 path->remainingsplats = numsplats;
2547 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
2549 qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
2556 // see if there are really any lights to render...
2557 if (enable && r_shadow_bouncegrid_static.integer)
2560 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2561 for (lightindex = 0;lightindex < range;lightindex++)
2563 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2564 if (!light || !(light->flags & flag))
2566 rtlight = &light->rtlight;
2567 // when static, we skip styled lights because they tend to change...
2568 if (rtlight->style > 0)
2570 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
2571 if (!VectorLength2(lightcolor))
2581 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
2583 qboolean s = r_shadow_bouncegrid_static.integer != 0;
2584 float spacing = bound(1.0f, s ? r_shadow_bouncegrid_static_spacing.value : r_shadow_bouncegrid_dynamic_spacing.value, 1024.0f);
2585 float quality = bound(0.0001f, (s ? r_shadow_bouncegrid_static_quality.value : r_shadow_bouncegrid_dynamic_quality.value), 1024.0f);
2586 float bounceminimumintensity = s ? r_shadow_bouncegrid_static_bounceminimumintensity.value : r_shadow_bouncegrid_dynamic_bounceminimumintensity.value;
2588 // prevent any garbage in alignment padded areas as we'll be using memcmp
2589 memset(settings, 0, sizeof(*settings));
2591 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
2592 settings->staticmode = s;
2593 settings->blur = r_shadow_bouncegrid_blur.integer != 0;
2594 settings->floatcolors = bound(0, r_shadow_bouncegrid_floatcolors.integer, 2);
2595 settings->lightpathsize_initial = bound(0.0f, r_shadow_bouncegrid_lightpathsize_initial.value, 1024.0f);
2596 settings->lightpathsize_conespread = bound(0.0f, r_shadow_bouncegrid_lightpathsize_conespread.value, 1024.0f);
2597 settings->bounceanglediffuse = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
2598 settings->directionalshading = (s ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_dynamic_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
2599 settings->dlightparticlemultiplier = s ? 0 : r_shadow_bouncegrid_dynamic_dlightparticlemultiplier.value;
2600 settings->hitmodels = s ? false : r_shadow_bouncegrid_dynamic_hitmodels.integer != 0;
2601 settings->includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
2602 settings->lightradiusscale = (s ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_dynamic_lightradiusscale.value);
2603 settings->maxbounce = (s ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_dynamic_maxbounce.integer);
2604 settings->particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
2605 settings->particleintensity = r_shadow_bouncegrid_particleintensity.value * (settings->directionalshading ? 4.0f : 1.0f) * 16384 / (spacing * spacing) / 262144.0f;
2606 settings->maxphotons = s ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_dynamic_maxphotons.integer;
2607 settings->energyperphoton = spacing * spacing / quality;
2608 settings->spacing[0] = spacing;
2609 settings->spacing[1] = spacing;
2610 settings->spacing[2] = spacing;
2611 settings->rng_type = r_shadow_bouncegrid_rng_type.integer;
2612 settings->rng_seed = r_shadow_bouncegrid_rng_seed.integer;
2613 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
2614 settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
2615 settings->normalizevectors = r_shadow_bouncegrid_normalizevectors.integer != 0;
2617 // bound the values for sanity
2618 settings->maxphotons = bound(1, settings->maxphotons, 25000000);
2619 settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
2620 settings->maxbounce = bound(0, settings->maxbounce, 16);
2621 settings->spacing[0] = bound(1, settings->spacing[0], 512);
2622 settings->spacing[1] = bound(1, settings->spacing[1], 512);
2623 settings->spacing[2] = bound(1, settings->spacing[2], 512);
2626 static void R_Shadow_BounceGrid_UpdateSpacing(void)
2637 r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
2639 // get the spacing values
2640 spacing[0] = settings->spacing[0];
2641 spacing[1] = settings->spacing[1];
2642 spacing[2] = settings->spacing[2];
2643 ispacing[0] = 1.0f / spacing[0];
2644 ispacing[1] = 1.0f / spacing[1];
2645 ispacing[2] = 1.0f / spacing[2];
2647 // calculate texture size enclosing entire world bounds at the spacing
2648 if (r_refdef.scene.worldmodel)
2652 qboolean bounds_set = false;
2656 // calculate bounds enclosing world lights as they should be noticably tighter
2657 // than the world bounds on maps with unlit monster containers (see e1m7 etc)
2658 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2659 for (lightindex = 0;lightindex < range;lightindex++)
2661 const vec_t *rtlmins, *rtlmaxs;
2663 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2667 rtlight = &light->rtlight;
2668 rtlmins = rtlight->cullmins;
2669 rtlmaxs = rtlight->cullmaxs;
2673 VectorCopy(rtlmins, mins);
2674 VectorCopy(rtlmaxs, maxs);
2679 mins[0] = min(mins[0], rtlmins[0]);
2680 mins[1] = min(mins[1], rtlmins[1]);
2681 mins[2] = min(mins[2], rtlmins[2]);
2682 maxs[0] = max(maxs[0], rtlmaxs[0]);
2683 maxs[1] = max(maxs[1], rtlmaxs[1]);
2684 maxs[2] = max(maxs[2], rtlmaxs[2]);
2688 // limit to no larger than the world bounds
2689 mins[0] = max(mins[0], r_refdef.scene.worldmodel->normalmins[0]);
2690 mins[1] = max(mins[1], r_refdef.scene.worldmodel->normalmins[1]);
2691 mins[2] = max(mins[2], r_refdef.scene.worldmodel->normalmins[2]);
2692 maxs[0] = min(maxs[0], r_refdef.scene.worldmodel->normalmaxs[0]);
2693 maxs[1] = min(maxs[1], r_refdef.scene.worldmodel->normalmaxs[1]);
2694 maxs[2] = min(maxs[2], r_refdef.scene.worldmodel->normalmaxs[2]);
2696 VectorMA(mins, -2.0f, spacing, mins);
2697 VectorMA(maxs, 2.0f, spacing, maxs);
2701 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
2702 VectorSet(maxs, 1048576.0f, 1048576.0f, 1048576.0f);
2704 VectorSubtract(maxs, mins, size);
2705 // now we can calculate the resolution we want
2706 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2707 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2708 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2709 // figure out the exact texture size (honoring power of 2 if required)
2710 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2711 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2712 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2713 if (vid.support.arb_texture_non_power_of_two)
2715 resolution[0] = c[0];
2716 resolution[1] = c[1];
2717 resolution[2] = c[2];
2721 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2722 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2723 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2725 size[0] = spacing[0] * resolution[0];
2726 size[1] = spacing[1] * resolution[1];
2727 size[2] = spacing[2] * resolution[2];
2729 // if dynamic we may or may not want to use the world bounds
2730 // if the dynamic size is smaller than the world bounds, use it instead
2731 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]))
2733 // we know the resolution we want
2734 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
2735 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
2736 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
2737 // now we can calculate the texture size (power of 2 if required)
2738 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2739 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2740 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2741 if (vid.support.arb_texture_non_power_of_two)
2743 resolution[0] = c[0];
2744 resolution[1] = c[1];
2745 resolution[2] = c[2];
2749 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2750 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2751 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2753 size[0] = spacing[0] * resolution[0];
2754 size[1] = spacing[1] * resolution[1];
2755 size[2] = spacing[2] * resolution[2];
2756 // center the rendering on the view
2757 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2758 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2759 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2762 // recalculate the maxs in case the resolution was not satisfactory
2763 VectorAdd(mins, size, maxs);
2765 // check if this changed the texture size
2766 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);
2767 r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
2768 VectorCopy(mins, r_shadow_bouncegrid_state.mins);
2769 VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
2770 VectorCopy(size, r_shadow_bouncegrid_state.size);
2771 VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
2772 VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
2773 VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
2775 // reallocate pixels for this update if needed...
2776 r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
2777 r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
2778 r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
2779 numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
2780 if (r_shadow_bouncegrid_state.numpixels != numpixels)
2782 if (r_shadow_bouncegrid_state.texture) R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL;
2783 r_shadow_bouncegrid_state.highpixels = NULL;
2784 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2785 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2786 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2787 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2788 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
2789 r_shadow_bouncegrid_state.maxsplatpaths = 0;
2790 r_shadow_bouncegrid_state.numpixels = numpixels;
2793 // update the bouncegrid matrix to put it in the world properly
2794 memset(m, 0, sizeof(m));
2795 m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
2796 m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
2797 m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
2798 m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
2799 m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
2800 m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
2802 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
2805 // enumerate world rtlights and sum the overall amount of light in the world,
2806 // from that we can calculate a scaling factor to fairly distribute photons
2807 // to all the lights
2809 // this modifies rtlight->photoncolor and rtlight->photons
2810 static void R_Shadow_BounceGrid_AssignPhotons(r_shadow_bouncegrid_settings_t *settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
2812 float normalphotonscaling;
2813 float photonscaling;
2814 float photonintensity;
2815 float photoncount = 0.0f;
2816 float lightintensity;
2822 unsigned int lightindex;
2825 normalphotonscaling = 1.0f / max(0.0001f, settings->energyperphoton);
2826 for (lightindex = 0;lightindex < range2;lightindex++)
2828 if (lightindex < range)
2830 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2833 rtlight = &light->rtlight;
2834 VectorClear(rtlight->bouncegrid_photoncolor);
2835 rtlight->bouncegrid_photons = 0;
2836 rtlight->bouncegrid_hits = 0;
2837 rtlight->bouncegrid_traces = 0;
2838 rtlight->bouncegrid_effectiveradius = 0;
2839 if (!(light->flags & flag))
2841 if (settings->staticmode)
2843 // when static, we skip styled lights because they tend to change...
2844 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2847 else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
2852 rtlight = r_refdef.scene.lights[lightindex - range];
2853 VectorClear(rtlight->bouncegrid_photoncolor);
2854 rtlight->bouncegrid_photons = 0;
2855 rtlight->bouncegrid_hits = 0;
2856 rtlight->bouncegrid_traces = 0;
2857 rtlight->bouncegrid_effectiveradius = 0;
2859 // draw only visible lights (major speedup)
2860 radius = rtlight->radius * settings->lightradiusscale;
2861 cullmins[0] = rtlight->shadoworigin[0] - radius;
2862 cullmins[1] = rtlight->shadoworigin[1] - radius;
2863 cullmins[2] = rtlight->shadoworigin[2] - radius;
2864 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2865 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2866 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2867 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2868 if (!settings->staticmode)
2870 // skip if the expanded light box does not touch any visible leafs
2871 if (r_refdef.scene.worldmodel
2872 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2873 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2875 // skip if the expanded light box is not visible to traceline
2876 // note that PrepareLight already did this check but for a smaller box, so we
2877 // end up casting more traces per frame per light when using bouncegrid, which
2878 // is probably fine (and they use the same timer)
2879 if (r_shadow_culllights_trace.integer)
2881 if (rtlight->trace_timer != realtime && R_CanSeeBox(rtlight->trace_timer == 0 ? r_shadow_culllights_trace_tempsamples.integer : r_shadow_culllights_trace_samples.integer, r_shadow_culllights_trace_eyejitter.value, r_shadow_culllights_trace_enlarge.value, r_shadow_culllights_trace_expand.value, r_shadow_culllights_trace_pad.value, r_refdef.view.origin, rtlight->cullmins, rtlight->cullmaxs))
2882 rtlight->trace_timer = realtime;
2883 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
2886 // skip if expanded light box is offscreen
2887 if (R_CullBox(cullmins, cullmaxs))
2889 // skip if overall light intensity is zero
2890 if (w * VectorLength2(rtlight->color) == 0.0f)
2893 // a light that does not emit any light before style is applied, can be
2894 // skipped entirely (it may just be a corona)
2895 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2897 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2898 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2899 // skip lights that will emit no photons
2900 if (!VectorLength2(rtlight->bouncegrid_photoncolor))
2902 // shoot particles from this light
2903 // use a calculation for the number of particles that will not
2904 // vary with lightstyle, otherwise we get randomized particle
2905 // distribution, the seeded random is only consistent for a
2906 // consistent number of particles on this light...
2907 s = rtlight->radius;
2908 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2909 if (lightindex >= range)
2910 lightintensity *= settings->dlightparticlemultiplier;
2911 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2912 photoncount += rtlight->bouncegrid_photons;
2913 VectorScale(rtlight->bouncegrid_photoncolor, settings->particleintensity * settings->energyperphoton, rtlight->bouncegrid_photoncolor);
2914 // if the lightstyle happens to be off right now, we can skip actually
2915 // firing the photons, but we did have to count them in the total.
2916 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2917 // rtlight->bouncegrid_photons = 0;
2919 // the user provided an energyperphoton value which we try to use
2920 // if that results in too many photons to shoot this frame, then we cap it
2921 // which causes photons to appear/disappear from frame to frame, so we don't
2922 // like doing that in the typical case
2923 photonscaling = 1.0f;
2924 photonintensity = 1.0f;
2925 if (photoncount > settings->maxphotons)
2927 photonscaling = settings->maxphotons / photoncount;
2928 photonintensity = 1.0f / photonscaling;
2931 // modify the lights to reflect our computed scaling
2932 for (lightindex = 0; lightindex < range2; lightindex++)
2934 if (lightindex < range)
2936 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2939 rtlight = &light->rtlight;
2942 rtlight = r_refdef.scene.lights[lightindex - range];
2943 rtlight->bouncegrid_photons *= photonscaling;
2944 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2948 static int R_Shadow_BounceGrid_SplatPathCompare(const void *pa, const void *pb)
2950 r_shadow_bouncegrid_splatpath_t *a = (r_shadow_bouncegrid_splatpath_t *)pa;
2951 r_shadow_bouncegrid_splatpath_t *b = (r_shadow_bouncegrid_splatpath_t *)pb;
2952 // we only really care about sorting by Z
2953 if (a->point[2] < b->point[2])
2955 if (a->point[2] > b->point[2])
2960 static void R_Shadow_BounceGrid_ClearPixels(void)
2962 // clear the highpixels array we'll be accumulating into
2963 if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2964 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2965 if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2966 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2967 r_shadow_bouncegrid_state.highpixels_index = 0;
2968 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2969 memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2972 static void R_Shadow_BounceGrid_PerformSplats(void)
2974 r_shadow_bouncegrid_splatpath_t *splatpaths = r_shadow_bouncegrid_state.splatpaths;
2975 r_shadow_bouncegrid_splatpath_t *splatpath;
2976 float *highpixels = r_shadow_bouncegrid_state.highpixels;
2977 int numsplatpaths = r_shadow_bouncegrid_state.numsplatpaths;
2982 vec_t lightpathsize_current;
2983 vec_t lightpathsize_perstep;
2984 float splatcolor[32];
2986 int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2987 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2991 // hush warnings about uninitialized data - pixelbands doesn't change but...
2992 memset(splatcolor, 0, sizeof(splatcolor));
2994 // we use this a lot, so get a local copy
2995 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2997 // sort the splats before we execute them, to reduce cache misses
2998 if (r_shadow_bouncegrid_sortlightpaths.integer)
2999 qsort(splatpaths, numsplatpaths, sizeof(*splatpaths), R_Shadow_BounceGrid_SplatPathCompare);
3001 splatpath = splatpaths;
3002 for (splatindex = 0;splatindex < numsplatpaths;splatindex++, splatpath++)
3004 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
3005 // accumulate average shotcolor
3006 VectorCopy(splatpath->splatdir, dir);
3007 splatcolor[ 0] = splatpath->splatcolor[0];
3008 splatcolor[ 1] = splatpath->splatcolor[1];
3009 splatcolor[ 2] = splatpath->splatcolor[2];
3010 splatcolor[ 3] = 0.0f;
3013 // store bentnormal in case the shader has a use for it,
3014 // bentnormal is an intensity-weighted average of the directions,
3015 // and will be normalized on conversion to texture pixels.
3016 splatcolor[ 4] = dir[0] * splatpath->splatintensity;
3017 splatcolor[ 5] = dir[1] * splatpath->splatintensity;
3018 splatcolor[ 6] = dir[2] * splatpath->splatintensity;
3019 splatcolor[ 7] = splatpath->splatintensity;
3020 // for each color component (R, G, B) calculate the amount that a
3021 // direction contributes
3022 splatcolor[ 8] = splatcolor[0] * max(0.0f, dir[0]);
3023 splatcolor[ 9] = splatcolor[0] * max(0.0f, dir[1]);
3024 splatcolor[10] = splatcolor[0] * max(0.0f, dir[2]);
3025 splatcolor[11] = 0.0f;
3026 splatcolor[12] = splatcolor[1] * max(0.0f, dir[0]);
3027 splatcolor[13] = splatcolor[1] * max(0.0f, dir[1]);
3028 splatcolor[14] = splatcolor[1] * max(0.0f, dir[2]);
3029 splatcolor[15] = 0.0f;
3030 splatcolor[16] = splatcolor[2] * max(0.0f, dir[0]);
3031 splatcolor[17] = splatcolor[2] * max(0.0f, dir[1]);
3032 splatcolor[18] = splatcolor[2] * max(0.0f, dir[2]);
3033 splatcolor[19] = 0.0f;
3034 // and do the same for negative directions
3035 splatcolor[20] = splatcolor[0] * max(0.0f, -dir[0]);
3036 splatcolor[21] = splatcolor[0] * max(0.0f, -dir[1]);
3037 splatcolor[22] = splatcolor[0] * max(0.0f, -dir[2]);
3038 splatcolor[23] = 0.0f;
3039 splatcolor[24] = splatcolor[1] * max(0.0f, -dir[0]);
3040 splatcolor[25] = splatcolor[1] * max(0.0f, -dir[1]);
3041 splatcolor[26] = splatcolor[1] * max(0.0f, -dir[2]);
3042 splatcolor[27] = 0.0f;
3043 splatcolor[28] = splatcolor[2] * max(0.0f, -dir[0]);
3044 splatcolor[29] = splatcolor[2] * max(0.0f, -dir[1]);
3045 splatcolor[30] = splatcolor[2] * max(0.0f, -dir[2]);
3046 splatcolor[31] = 0.0f;
3048 // calculate the number of steps we need to traverse this distance
3049 VectorCopy(splatpath->point, steppos);
3050 VectorCopy(splatpath->step, stepdelta);
3051 numsteps = splatpath->remainingsplats;
3052 lightpathsize_current = splatpath->splatsize_current + 1.0f; // add 1.0 for the gradient fade around the sphere
3053 lightpathsize_perstep = splatpath->splatsize_perstep;
3054 for (step = 0;step < numsteps;step++)
3056 // the middle row/column/layer of each splat are full intensity
3059 if (lightpathsize_current > MAXBOUNCEGRIDSPLATSIZE)
3060 lightpathsize_current = MAXBOUNCEGRIDSPLATSIZE;
3061 splatmins[0] = max(1.0f, steppos[0] - lightpathsize_current * 0.5f);
3062 splatmins[1] = max(1.0f, steppos[1] - lightpathsize_current * 0.5f);
3063 splatmins[2] = max(1.0f, steppos[2] - lightpathsize_current * 0.5f);
3064 splatmaxs[0] = min(steppos[0] + lightpathsize_current * 0.5f, resolution[0] - 1.0f);
3065 splatmaxs[1] = min(steppos[1] + lightpathsize_current * 0.5f, resolution[1] - 1.0f);
3066 splatmaxs[2] = min(steppos[2] + lightpathsize_current * 0.5f, resolution[2] - 1.0f);
3067 if (splatmaxs[0] > splatmins[0] && splatmaxs[1] > splatmins[1] && splatmaxs[2] > splatmins[2])
3069 // it is within bounds... do the real work now
3070 int xi, yi, zi, band, row;
3074 float colorscale = 1.0f / lightpathsize_current;
3075 r_refdef.stats[r_stat_bouncegrid_splats]++;
3076 // accumulate light onto the pixels
3077 for (zi = (int)floor(splatmins[2]);zi < splatmaxs[2];zi++)
3079 pixelpos[2] = zi + 0.5f;
3080 for (yi = (int)floor(splatmins[1]); yi < splatmaxs[1]; yi++)
3082 pixelpos[1] = yi + 0.5f;
3083 row = (zi*resolution[1] + yi)*resolution[0];
3084 for (xi = (int)floor(splatmins[0]); xi < splatmaxs[0]; xi++)
3086 pixelpos[0] = xi + 0.5f;
3087 // simple radial antialiased sphere - linear gradient fade over 1 pixel from the edge
3088 w = lightpathsize_current - VectorDistance(pixelpos, steppos);
3094 p = highpixels + 4 * (row + xi);
3095 for (band = 0; band < pixelbands; band++, p += pixelsperband * 4)
3097 // add to the pixel color
3098 p[0] += splatcolor[band * 4 + 0] * w;
3099 p[1] += splatcolor[band * 4 + 1] * w;
3100 p[2] += splatcolor[band * 4 + 2] * w;
3101 p[3] += splatcolor[band * 4 + 3] * w;
3108 VectorAdd(steppos, stepdelta, steppos);
3109 lightpathsize_current += lightpathsize_perstep;
3114 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
3116 const float *inpixel;
3118 int pixelbands = r_shadow_bouncegrid_state.pixelbands;
3121 unsigned int x, y, z;
3122 unsigned int resolution[3];
3123 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3124 for (pixelband = 0;pixelband < pixelbands;pixelband++)
3126 for (z = 1;z < resolution[2]-1;z++)
3128 for (y = 1;y < resolution[1]-1;y++)
3131 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3132 inpixel = inpixels + 4*index;
3133 outpixel = outpixels + 4*index;
3134 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
3136 outpixel[0] = (inpixel[0] + inpixel[ off] + inpixel[0-off]) * (1.0f / 3.0);
3137 outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
3138 outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
3139 outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
3146 static void R_Shadow_BounceGrid_BlurPixels(void)
3149 unsigned int resolution[3];
3151 if (!r_shadow_bouncegrid_state.settings.blur)
3154 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3156 pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3157 pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
3158 pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3159 pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
3162 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
3164 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
3166 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
3168 // toggle the state, highpixels now points to pixels[3] result
3169 r_shadow_bouncegrid_state.highpixels_index ^= 1;
3170 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
3173 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
3175 int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
3176 unsigned char *pixelsbgra8 = NULL;
3177 unsigned char *pixelbgra8;
3178 unsigned short *pixelsrgba16f = NULL;
3179 unsigned short *pixelrgba16f;
3180 float *pixelsrgba32f = NULL;
3181 float *highpixels = r_shadow_bouncegrid_state.highpixels;
3184 unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
3185 unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
3186 unsigned int pixelband;
3187 unsigned int x, y, z;
3188 unsigned int index, bandindex;
3189 unsigned int resolution[3];
3191 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
3193 if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
3195 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3196 r_shadow_bouncegrid_state.texture = NULL;
3199 // if bentnormals exist, we need to normalize and bias them for the shader
3203 for (z = 0;z < resolution[2]-1;z++)
3205 for (y = 0;y < resolution[1]-1;y++)
3208 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3209 highpixel = highpixels + 4*index;
3210 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3212 // only convert pixels that were hit by photons
3213 if (highpixel[3] != 0.0f)
3214 VectorNormalize(highpixel);
3215 VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
3216 highpixel[pixelsperband * 4 + 3] = 1.0f;
3222 // start by clearing the pixels array - we won't be writing to all of it
3224 // then process only the pixels that have at least some color, skipping
3225 // the higher bands for speed on pixels that are black
3226 switch (floatcolors)
3229 if (r_shadow_bouncegrid_state.u8pixels == NULL)
3230 r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
3231 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
3232 for (pixelband = 0;pixelband < pixelbands;pixelband++)
3235 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
3237 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
3239 for (z = 1;z < resolution[2]-1;z++)
3241 for (y = 1;y < resolution[1]-1;y++)
3245 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3246 highpixel = highpixels + 4*index;
3247 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3249 // only convert pixels that were hit by photons
3250 if (VectorLength2(highpixel))
3252 // normalize the bentnormal now
3255 VectorNormalize(highpixel + pixelsperband * 4);
3256 highpixel[pixelsperband * 4 + 3] = 1.0f;
3258 // process all of the pixelbands for this pixel
3259 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3261 pixelbgra8 = pixelsbgra8 + 4*bandindex;
3262 bandpixel = highpixels + 4*bandindex;
3263 c[0] = (int)(bandpixel[0]*256.0f);
3264 c[1] = (int)(bandpixel[1]*256.0f);
3265 c[2] = (int)(bandpixel[2]*256.0f);
3266 c[3] = (int)(bandpixel[3]*256.0f);
3267 pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
3268 pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
3269 pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
3270 pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
3277 if (!r_shadow_bouncegrid_state.createtexture)
3278 R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3280 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);
3283 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
3284 r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3285 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
3286 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
3287 for (z = 1;z < resolution[2]-1;z++)
3289 for (y = 1;y < resolution[1]-1;y++)
3293 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
3294 highpixel = highpixels + 4*index;
3295 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
3297 // only convert pixels that were hit by photons
3298 if (VectorLength2(highpixel))
3300 // process all of the pixelbands for this pixel
3301 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
3303 // time to have fun with IEEE 754 bit hacking...
3306 unsigned int raw[4];
3308 pixelrgba16f = pixelsrgba16f + 4*bandindex;
3309 bandpixel = highpixels + 4*bandindex;
3310 VectorCopy4(bandpixel, u.f);
3311 VectorCopy4(u.raw, c);
3312 // this math supports negative numbers, snaps denormals to zero
3313 //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
3314 //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
3315 //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
3316 //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
3317 // this math does not support negative
3318 pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
3319 pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
3320 pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
3321 pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
3328 if (!r_shadow_bouncegrid_state.createtexture)
3329 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3331 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);
3334 // our native format happens to match, so this is easy.
3335 pixelsrgba32f = highpixels;
3337 if (!r_shadow_bouncegrid_state.createtexture)
3338 R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
3340 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);
3344 r_shadow_bouncegrid_state.lastupdatetime = realtime;
3347 static void R_Shadow_BounceGrid_TracePhotons(r_shadow_bouncegrid_settings_t settings, unsigned int range, unsigned int range1, unsigned int range2, int flag)
3349 vec3_t bouncerandom[10];
3352 int hitsupercontentsmask;
3353 int skipsupercontentsmask;
3354 int skipmaterialflagsmask;
3358 float bounceminimumintensity2;
3360 //trace_t cliptrace2;
3361 //trace_t cliptrace3;
3362 unsigned int lightindex;
3364 randomseed_t randomseed;
3366 vec3_t baseshotcolor;
3372 vec_t distancetraveled;
3376 // compute a seed for the unstable random modes
3377 Math_RandomSeed_FromInts(&randomseed, 0, 0, 0, realtime * 1000.0);
3378 seed = realtime * 1000.0;
3380 r_shadow_bouncegrid_state.numsplatpaths = 0;
3382 // figure out what we want to interact with
3383 if (settings.hitmodels)
3384 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
3386 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
3387 skipsupercontentsmask = 0;
3388 skipmaterialflagsmask = MATERIALFLAGMASK_TRANSLUCENT;
3389 maxbounce = settings.maxbounce;
3391 for (lightindex = 0;lightindex < range2;lightindex++)
3393 if (lightindex < range)
3395 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3398 rtlight = &light->rtlight;
3401 rtlight = r_refdef.scene.lights[lightindex - range];
3402 // note that this code used to keep track of residual photons and
3403 // distribute them evenly to achieve exactly a desired photon count,
3404 // but that caused unwanted flickering in dynamic mode
3405 shootparticles = (int)floor(rtlight->bouncegrid_photons);
3406 // skip if we won't be shooting any photons
3407 if (!shootparticles)
3409 radius = rtlight->radius * settings.lightradiusscale;
3410 //s = settings.particleintensity / shootparticles;
3411 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
3412 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
3413 if (VectorLength2(baseshotcolor) <= 0.0f)
3415 r_refdef.stats[r_stat_bouncegrid_lights]++;
3416 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
3417 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
3418 bounceminimumintensity2 = VectorLength(baseshotcolor) * settings.bounceminimumintensity2;
3420 // for seeded random we start the RNG with the position of the light
3421 if (settings.rng_seed >= 0)
3429 u.f[0] = rtlight->shadoworigin[0];
3430 u.f[1] = rtlight->shadoworigin[1];
3431 u.f[2] = rtlight->shadoworigin[2];
3433 switch (settings.rng_type)
3437 // we have to shift the seed provided by the user because the result must be odd
3438 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3] ^ (settings.rng_seed << 1));
3441 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3] ^ settings.rng_seed;
3446 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
3448 VectorCopy(baseshotcolor, shotcolor);
3449 VectorCopy(rtlight->shadoworigin, clipstart);
3450 switch (settings.rng_type)
3454 VectorLehmerRandom(&randomseed, clipend);
3455 if (settings.bounceanglediffuse)
3457 // we want random to be stable, so we still have to do all the random we would have done
3458 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3459 VectorLehmerRandom(&randomseed, bouncerandom[bouncecount]);
3463 VectorCheeseRandom(seed, clipend);
3464 if (settings.bounceanglediffuse)
3466 // we want random to be stable, so we still have to do all the random we would have done
3467 for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
3468 VectorCheeseRandom(seed, bouncerandom[bouncecount]);
3473 // we want a uniform distribution spherically, not merely within the sphere
3474 if (settings.normalizevectors)
3475 VectorNormalize(clipend);
3477 VectorMA(clipstart, radius, clipend, clipend);
3478 distancetraveled = 0.0f;
3479 for (bouncecount = 0;;bouncecount++)
3481 r_refdef.stats[r_stat_bouncegrid_traces]++;
3482 rtlight->bouncegrid_traces++;
3483 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
3484 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
3485 if (settings.staticmode || settings.rng_seed < 0)
3487 // static mode fires a LOT of rays but none of them are identical, so they are not cached
3488 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
3489 cliptrace = CL_TraceLine(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), NULL, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, collision_extendmovelength.value, true, false, NULL, true, true);
3493 // dynamic mode fires many rays and most will match the cache from the previous frame
3494 cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
3496 if (bouncecount > 0 || settings.includedirectlighting)
3499 VectorCopy(cliptrace.endpos, hitpos);
3500 R_Shadow_BounceGrid_AddSplatPath(clipstart, hitpos, shotcolor, distancetraveled);
3502 distancetraveled += VectorDistance(clipstart, cliptrace.endpos);
3503 s = VectorDistance(rtlight->shadoworigin, cliptrace.endpos);
3504 if (rtlight->bouncegrid_effectiveradius < s)
3505 rtlight->bouncegrid_effectiveradius = s;
3506 if (cliptrace.fraction >= 1.0f)
3508 r_refdef.stats[r_stat_bouncegrid_hits]++;
3509 rtlight->bouncegrid_hits++;
3510 if (bouncecount >= maxbounce)
3512 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
3513 // also clamp the resulting color to never add energy, even if the user requests extreme values
3514 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
3515 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
3517 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
3518 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
3519 surfcolor[0] = min(surfcolor[0], 1.0f);
3520 surfcolor[1] = min(surfcolor[1], 1.0f);
3521 surfcolor[2] = min(surfcolor[2], 1.0f);
3522 VectorMultiply(shotcolor, surfcolor, shotcolor);
3523 if (VectorLength2(shotcolor) <= bounceminimumintensity2)
3525 r_refdef.stats[r_stat_bouncegrid_bounces]++;
3526 if (settings.bounceanglediffuse)
3528 // random direction, primarily along plane normal
3529 s = VectorDistance(cliptrace.endpos, clipend);
3530 VectorMA(cliptrace.plane.normal, 0.95f, bouncerandom[bouncecount], clipend);
3531 VectorNormalize(clipend);
3532 VectorScale(clipend, s, clipend);
3536 // reflect the remaining portion of the line across plane normal
3537 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
3538 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
3540 // calculate the new line start and end
3541 VectorCopy(cliptrace.endpos, clipstart);
3542 VectorAdd(clipstart, clipend, clipend);
3548 void R_Shadow_UpdateBounceGridTexture(void)
3550 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3551 r_shadow_bouncegrid_settings_t settings;
3552 qboolean enable = false;
3553 qboolean settingschanged;
3554 unsigned int range; // number of world lights
3555 unsigned int range1; // number of dynamic lights (or zero if disabled)
3556 unsigned int range2; // range+range1
3558 enable = R_Shadow_BounceGrid_CheckEnable(flag);
3560 R_Shadow_BounceGrid_GenerateSettings(&settings);
3562 // changing intensity does not require an update
3563 r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
3565 settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
3567 // when settings change, we free everything as it is just simpler that way.
3568 if (settingschanged || !enable)
3570 // not enabled, make sure we free anything we don't need anymore.
3571 if (r_shadow_bouncegrid_state.texture)
3573 R_FreeTexture(r_shadow_bouncegrid_state.texture);
3574 r_shadow_bouncegrid_state.texture = NULL;
3576 r_shadow_bouncegrid_state.highpixels = NULL;
3577 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
3578 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
3579 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
3580 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
3581 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
3582 r_shadow_bouncegrid_state.maxsplatpaths = 0;
3583 r_shadow_bouncegrid_state.numpixels = 0;
3584 r_shadow_bouncegrid_state.directional = false;
3590 // if all the settings seem identical to the previous update, return
3591 if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
3594 // store the new settings
3595 r_shadow_bouncegrid_state.settings = settings;
3597 R_Shadow_BounceGrid_UpdateSpacing();
3599 // get the range of light numbers we'll be looping over:
3600 // range = static lights
3601 // range1 = dynamic lights (optional)
3602 // range2 = range + range1
3603 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3604 range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
3605 range2 = range + range1;
3607 // calculate weighting factors for distributing photons among the lights
3608 R_Shadow_BounceGrid_AssignPhotons(&settings, range, range1, range2, flag);
3610 // trace the photons from lights and accumulate illumination
3611 R_Shadow_BounceGrid_TracePhotons(settings, range, range1, range2, flag);
3613 // clear the texture
3614 R_Shadow_BounceGrid_ClearPixels();
3616 // accumulate the light splatting into texture
3617 R_Shadow_BounceGrid_PerformSplats();
3619 // apply a mild blur filter to the texture
3620 R_Shadow_BounceGrid_BlurPixels();
3622 // convert the pixels to lower precision and upload the texture
3623 R_Shadow_BounceGrid_ConvertPixelsAndUpload();
3625 // after we compute the static lighting we don't need to keep the highpixels array around
3626 if (settings.staticmode)
3628 r_shadow_bouncegrid_state.highpixels = NULL;
3629 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
3630 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
3631 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
3632 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
3633 if (r_shadow_bouncegrid_state.splatpaths) Mem_Free(r_shadow_bouncegrid_state.splatpaths); r_shadow_bouncegrid_state.splatpaths = NULL;
3634 r_shadow_bouncegrid_state.maxsplatpaths = 0;
3638 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
3640 R_Shadow_RenderMode_Reset();
3641 GL_BlendFunc(GL_ONE, GL_ONE);
3642 GL_DepthRange(0, 1);
3643 GL_DepthTest(r_showshadowvolumes.integer < 2);
3644 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
3645 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
3646 GL_CullFace(GL_NONE);
3647 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
3650 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
3652 R_Shadow_RenderMode_Reset();
3653 GL_BlendFunc(GL_ONE, GL_ONE);
3654 GL_DepthRange(0, 1);
3655 GL_DepthTest(r_showlighting.integer < 2);
3656 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
3658 GL_DepthFunc(GL_EQUAL);
3659 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
3660 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
3663 void R_Shadow_RenderMode_End(void)
3665 R_Shadow_RenderMode_Reset();
3666 R_Shadow_RenderMode_ActiveLight(NULL);
3668 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3669 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3672 int bboxedges[12][2] =
3691 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
3693 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
3695 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
3696 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
3697 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
3698 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
3701 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
3702 return true; // invisible
3703 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
3704 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
3705 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
3706 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
3707 r_refdef.stats[r_stat_lights_scissored]++;
3711 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
3714 const float *vertex3f;
3715 const float *normal3f;
3717 float dist, dot, distintensity, shadeintensity, v[3], n[3];
3718 switch (r_shadow_rendermode)
3720 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3721 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3722 if (VectorLength2(diffusecolor) > 0)
3724 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)
3726 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3727 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3728 if ((dot = DotProduct(n, v)) < 0)
3730 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3731 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
3734 VectorCopy(ambientcolor, color4f);
3735 if (r_refdef.fogenabled)
3738 f = RSurf_FogVertex(vertex3f);
3739 VectorScale(color4f, f, color4f);
3746 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3748 VectorCopy(ambientcolor, color4f);
3749 if (r_refdef.fogenabled)
3752 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3753 f = RSurf_FogVertex(vertex3f);
3754 VectorScale(color4f + 4*i, f, color4f);
3760 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3761 if (VectorLength2(diffusecolor) > 0)
3763 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)
3765 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3766 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3768 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3769 if ((dot = DotProduct(n, v)) < 0)
3771 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3772 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3773 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3774 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3778 color4f[0] = ambientcolor[0] * distintensity;
3779 color4f[1] = ambientcolor[1] * distintensity;
3780 color4f[2] = ambientcolor[2] * distintensity;
3782 if (r_refdef.fogenabled)
3785 f = RSurf_FogVertex(vertex3f);
3786 VectorScale(color4f, f, color4f);
3790 VectorClear(color4f);
3796 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3798 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3799 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3801 color4f[0] = ambientcolor[0] * distintensity;
3802 color4f[1] = ambientcolor[1] * distintensity;
3803 color4f[2] = ambientcolor[2] * distintensity;
3804 if (r_refdef.fogenabled)
3807 f = RSurf_FogVertex(vertex3f);
3808 VectorScale(color4f, f, color4f);
3812 VectorClear(color4f);
3817 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3818 if (VectorLength2(diffusecolor) > 0)
3820 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)
3822 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3823 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3825 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3826 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3827 if ((dot = DotProduct(n, v)) < 0)
3829 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3830 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3831 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3832 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3836 color4f[0] = ambientcolor[0] * distintensity;
3837 color4f[1] = ambientcolor[1] * distintensity;
3838 color4f[2] = ambientcolor[2] * distintensity;
3840 if (r_refdef.fogenabled)
3843 f = RSurf_FogVertex(vertex3f);
3844 VectorScale(color4f, f, color4f);
3848 VectorClear(color4f);
3854 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3856 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3857 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3859 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3860 color4f[0] = ambientcolor[0] * distintensity;
3861 color4f[1] = ambientcolor[1] * distintensity;
3862 color4f[2] = ambientcolor[2] * distintensity;
3863 if (r_refdef.fogenabled)
3866 f = RSurf_FogVertex(vertex3f);
3867 VectorScale(color4f, f, color4f);
3871 VectorClear(color4f);
3881 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3883 // used to display how many times a surface is lit for level design purposes
3884 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3885 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3889 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const float ambientcolor[3], const float diffusecolor[3], const float specularcolor[3])
3891 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3892 R_SetupShader_Surface(ambientcolor, diffusecolor, specularcolor, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
3896 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3903 int newnumtriangles;
3907 int maxtriangles = 1024;
3908 int newelements[1024*3];
3909 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3910 for (renders = 0;renders < 4;renders++)
3915 newnumtriangles = 0;
3917 // due to low fillrate on the cards this vertex lighting path is
3918 // designed for, we manually cull all triangles that do not
3919 // contain a lit vertex
3920 // this builds batches of triangles from multiple surfaces and
3921 // renders them at once
3922 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3924 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3926 if (newnumtriangles)
3928 newfirstvertex = min(newfirstvertex, e[0]);
3929 newlastvertex = max(newlastvertex, e[0]);
3933 newfirstvertex = e[0];
3934 newlastvertex = e[0];
3936 newfirstvertex = min(newfirstvertex, e[1]);
3937 newlastvertex = max(newlastvertex, e[1]);
3938 newfirstvertex = min(newfirstvertex, e[2]);
3939 newlastvertex = max(newlastvertex, e[2]);
3945 if (newnumtriangles >= maxtriangles)
3947 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3948 newnumtriangles = 0;
3954 if (newnumtriangles >= 1)
3956 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3959 // if we couldn't find any lit triangles, exit early
3962 // now reduce the intensity for the next overbright pass
3963 // we have to clamp to 0 here incase the drivers have improper
3964 // handling of negative colors
3965 // (some old drivers even have improper handling of >1 color)
3967 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3969 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3971 c[0] = max(0, c[0] - 1);
3972 c[1] = max(0, c[1] - 1);
3973 c[2] = max(0, c[2] - 1);
3985 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const float ambientcolor[3], const float diffusecolor[3])
3987 // OpenGL 1.1 path (anything)
3988 float ambientcolorbase[3], diffusecolorbase[3];
3989 float ambientcolorpants[3], diffusecolorpants[3];
3990 float ambientcolorshirt[3], diffusecolorshirt[3];
3991 const float *surfacepants = rsurface.texture->render_colormap_pants;
3992 const float *surfaceshirt = rsurface.texture->render_colormap_shirt;
3993 rtexture_t *basetexture = rsurface.texture->basetexture;
3994 rtexture_t *pantstexture = rsurface.texture->pantstexture;
3995 rtexture_t *shirttexture = rsurface.texture->shirttexture;
3996 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3997 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3998 VectorCopy(ambientcolor, ambientcolorbase);
3999 VectorCopy(diffusecolor, diffusecolorbase);
4000 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
4001 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
4002 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
4003 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
4004 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (VectorLength2(diffusecolor) > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
4005 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
4006 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4007 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
4008 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
4009 R_Mesh_TexBind(0, basetexture);
4010 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
4011 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
4012 switch(r_shadow_rendermode)
4014 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
4015 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
4016 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
4017 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
4018 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4020 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
4021 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
4022 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
4023 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
4024 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4026 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
4027 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
4028 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
4029 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
4030 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
4032 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
4037 //R_Mesh_TexBind(0, basetexture);
4038 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
4041 R_Mesh_TexBind(0, pantstexture);
4042 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
4046 R_Mesh_TexBind(0, shirttexture);
4047 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
4051 extern cvar_t gl_lightmaps;
4052 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
4055 float ambientcolor[3], diffusecolor[3], specularcolor[3];
4056 VectorM(rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient, rsurface.texture->render_rtlight_diffuse, ambientcolor);
4057 VectorM(rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient), rsurface.texture->render_rtlight_diffuse, diffusecolor);
4058 VectorM(rsurface.rtlight->specularscale, rsurface.texture->render_rtlight_specular, specularcolor);
4059 if (!r_shadow_usenormalmap.integer)
4061 VectorMAM(1.0f, ambientcolor, 1.0f, diffusecolor, ambientcolor);
4062 VectorClear(diffusecolor);
4063 VectorClear(specularcolor);
4065 VectorMultiply(ambientcolor, rsurface.rtlight->currentcolor, ambientcolor);
4066 VectorMultiply(diffusecolor, rsurface.rtlight->currentcolor, diffusecolor);
4067 VectorMultiply(specularcolor, rsurface.rtlight->currentcolor, specularcolor);
4068 if (VectorLength2(ambientcolor) + VectorLength2(diffusecolor) + VectorLength2(specularcolor) < (1.0f / 1048576.0f))
4070 negated = (rsurface.rtlight->currentcolor[0] + rsurface.rtlight->currentcolor[1] + rsurface.rtlight->currentcolor[2] < 0) && vid.support.ext_blend_subtract;
4073 VectorNegate(ambientcolor, ambientcolor);
4074 VectorNegate(diffusecolor, diffusecolor);
4075 VectorNegate(specularcolor, specularcolor);
4076 GL_BlendEquationSubtract(true);
4078 RSurf_SetupDepthAndCulling();
4079 switch (r_shadow_rendermode)
4081 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
4082 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
4083 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
4085 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
4086 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, ambientcolor, diffusecolor, specularcolor);
4088 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
4089 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
4090 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
4091 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
4092 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, ambientcolor, diffusecolor);
4095 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
4099 GL_BlendEquationSubtract(false);
4102 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)
4104 matrix4x4_t tempmatrix = *matrix;
4105 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
4107 // if this light has been compiled before, free the associated data
4108 R_RTLight_Uncompile(rtlight);
4110 // clear it completely to avoid any lingering data
4111 memset(rtlight, 0, sizeof(*rtlight));
4113 // copy the properties
4114 rtlight->matrix_lighttoworld = tempmatrix;
4115 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
4116 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
4117 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
4118 VectorCopy(color, rtlight->color);
4119 rtlight->cubemapname[0] = 0;
4120 if (cubemapname && cubemapname[0])
4121 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
4122 rtlight->shadow = shadow;
4123 rtlight->corona = corona;
4124 rtlight->style = style;
4125 rtlight->isstatic = isstatic;
4126 rtlight->coronasizescale = coronasizescale;
4127 rtlight->ambientscale = ambientscale;
4128 rtlight->diffusescale = diffusescale;
4129 rtlight->specularscale = specularscale;
4130 rtlight->flags = flags;
4132 // compute derived data
4133 //rtlight->cullradius = rtlight->radius;
4134 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
4135 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
4136 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
4137 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
4138 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
4139 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
4140 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
4143 // compiles rtlight geometry
4144 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
4145 void R_RTLight_Compile(rtlight_t *rtlight)
4148 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
4149 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
4150 entity_render_t *ent = r_refdef.scene.worldentity;
4151 dp_model_t *model = r_refdef.scene.worldmodel;
4152 unsigned char *data;
4155 // compile the light
4156 rtlight->compiled = true;
4157 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
4158 rtlight->static_numleafs = 0;
4159 rtlight->static_numleafpvsbytes = 0;
4160 rtlight->static_leaflist = NULL;
4161 rtlight->static_leafpvs = NULL;
4162 rtlight->static_numsurfaces = 0;
4163 rtlight->static_surfacelist = NULL;
4164 rtlight->static_shadowmap_receivers = 0x3F;
4165 rtlight->static_shadowmap_casters = 0x3F;
4166 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
4167 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
4168 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
4169 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
4170 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
4171 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
4173 if (model && model->GetLightInfo)
4175 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
4176 r_shadow_compilingrtlight = rtlight;
4177 R_FrameData_SetMark();
4178 model->GetLightInfo(ent, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs, 0, NULL, rtlight->shadow == 0);
4179 R_FrameData_ReturnToMark();
4180 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
4181 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
4182 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
4183 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
4184 rtlight->static_numsurfaces = numsurfaces;
4185 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
4186 rtlight->static_numleafs = numleafs;
4187 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
4188 rtlight->static_numleafpvsbytes = numleafpvsbytes;
4189 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
4190 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
4191 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
4192 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
4193 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
4194 if (rtlight->static_numsurfaces)
4195 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
4196 if (rtlight->static_numleafs)
4197 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
4198 if (rtlight->static_numleafpvsbytes)
4199 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
4200 if (rtlight->static_numshadowtrispvsbytes)
4201 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
4202 if (rtlight->static_numlighttrispvsbytes)
4203 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
4204 R_FrameData_SetMark();
4205 switch (rtlight->shadowmode)
4207 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4208 if (model->CompileShadowMap && rtlight->shadow)
4209 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
4212 if (model->CompileShadowVolume && rtlight->shadow)
4213 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
4216 R_FrameData_ReturnToMark();
4217 // now we're done compiling the rtlight
4218 r_shadow_compilingrtlight = NULL;
4222 // use smallest available cullradius - box radius or light radius
4223 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
4224 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
4226 shadowzpasstris = 0;
4227 if (rtlight->static_meshchain_shadow_zpass)
4228 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
4229 shadowzpasstris += mesh->numtriangles;
4231 shadowzfailtris = 0;
4232 if (rtlight->static_meshchain_shadow_zfail)
4233 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
4234 shadowzfailtris += mesh->numtriangles;
4237 if (rtlight->static_numlighttrispvsbytes)
4238 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
4239 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
4243 if (rtlight->static_numshadowtrispvsbytes)
4244 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
4245 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
4248 if (developer_extra.integer)
4249 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);
4252 void R_RTLight_Uncompile(rtlight_t *rtlight)
4254 if (rtlight->compiled)
4256 if (rtlight->static_meshchain_shadow_zpass)
4257 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
4258 rtlight->static_meshchain_shadow_zpass = NULL;
4259 if (rtlight->static_meshchain_shadow_zfail)
4260 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
4261 rtlight->static_meshchain_shadow_zfail = NULL;
4262 if (rtlight->static_meshchain_shadow_shadowmap)
4263 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
4264 rtlight->static_meshchain_shadow_shadowmap = NULL;
4265 // these allocations are grouped
4266 if (rtlight->static_surfacelist)
4267 Mem_Free(rtlight->static_surfacelist);
4268 rtlight->static_numleafs = 0;
4269 rtlight->static_numleafpvsbytes = 0;
4270 rtlight->static_leaflist = NULL;
4271 rtlight->static_leafpvs = NULL;
4272 rtlight->static_numsurfaces = 0;
4273 rtlight->static_surfacelist = NULL;
4274 rtlight->static_numshadowtrispvsbytes = 0;
4275 rtlight->static_shadowtrispvs = NULL;
4276 rtlight->static_numlighttrispvsbytes = 0;
4277 rtlight->static_lighttrispvs = NULL;
4278 rtlight->compiled = false;
4282 void R_Shadow_UncompileWorldLights(void)
4286 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4287 for (lightindex = 0;lightindex < range;lightindex++)
4289 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4292 R_RTLight_Uncompile(&light->rtlight);
4296 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
4300 // reset the count of frustum planes
4301 // see rtlight->cached_frustumplanes definition for how much this array
4303 rtlight->cached_numfrustumplanes = 0;
4305 if (r_trippy.integer)
4308 // haven't implemented a culling path for ortho rendering
4309 if (!r_refdef.view.useperspective)
4311 // check if the light is on screen and copy the 4 planes if it is
4312 for (i = 0;i < 4;i++)
4313 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4316 for (i = 0;i < 4;i++)
4317 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4322 // generate a deformed frustum that includes the light origin, this is
4323 // used to cull shadow casting surfaces that can not possibly cast a
4324 // shadow onto the visible light-receiving surfaces, which can be a
4327 // if the light origin is onscreen the result will be 4 planes exactly
4328 // if the light origin is offscreen on only one axis the result will
4329 // be exactly 5 planes (split-side case)
4330 // if the light origin is offscreen on two axes the result will be
4331 // exactly 4 planes (stretched corner case)
4332 for (i = 0;i < 4;i++)
4334 // quickly reject standard frustum planes that put the light
4335 // origin outside the frustum
4336 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4339 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4341 // if all the standard frustum planes were accepted, the light is onscreen
4342 // otherwise we need to generate some more planes below...
4343 if (rtlight->cached_numfrustumplanes < 4)
4345 // at least one of the stock frustum planes failed, so we need to
4346 // create one or two custom planes to enclose the light origin
4347 for (i = 0;i < 4;i++)
4349 // create a plane using the view origin and light origin, and a
4350 // single point from the frustum corner set
4351 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
4352 VectorNormalize(plane.normal);
4353 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
4354 // see if this plane is backwards and flip it if so
4355 for (j = 0;j < 4;j++)
4356 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4360 VectorNegate(plane.normal, plane.normal);
4362 // flipped plane, test again to see if it is now valid
4363 for (j = 0;j < 4;j++)
4364 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4366 // if the plane is still not valid, then it is dividing the
4367 // frustum and has to be rejected
4371 // we have created a valid plane, compute extra info
4372 PlaneClassify(&plane);
4374 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4376 // if we've found 5 frustum planes then we have constructed a
4377 // proper split-side case and do not need to keep searching for
4378 // planes to enclose the light origin
4379 if (rtlight->cached_numfrustumplanes == 5)
4387 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
4389 plane = rtlight->cached_frustumplanes[i];
4390 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));
4395 // now add the light-space box planes if the light box is rotated, as any
4396 // caster outside the oriented light box is irrelevant (even if it passed
4397 // the worldspace light box, which is axial)
4398 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
4400 for (i = 0;i < 6;i++)
4404 v[i >> 1] = (i & 1) ? -1 : 1;
4405 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
4406 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
4407 plane.dist = VectorNormalizeLength(plane.normal);
4408 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
4409 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4415 // add the world-space reduced box planes
4416 for (i = 0;i < 6;i++)
4418 VectorClear(plane.normal);
4419 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
4420 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
4421 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4430 // reduce all plane distances to tightly fit the rtlight cull box, which
4432 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4433 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4434 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4435 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4436 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4437 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4438 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4439 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4440 oldnum = rtlight->cached_numfrustumplanes;
4441 rtlight->cached_numfrustumplanes = 0;
4442 for (j = 0;j < oldnum;j++)
4444 // find the nearest point on the box to this plane
4445 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
4446 for (i = 1;i < 8;i++)
4448 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
4449 if (bestdist > dist)
4452 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);
4453 // if the nearest point is near or behind the plane, we want this
4454 // plane, otherwise the plane is useless as it won't cull anything
4455 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
4457 PlaneClassify(&rtlight->cached_frustumplanes[j]);
4458 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
4465 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
4469 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4471 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4474 GL_CullFace(GL_NONE);
4475 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
4476 for (;mesh;mesh = mesh->next)
4478 if (!mesh->sidetotals[r_shadow_shadowmapside])
4480 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
4481 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4482 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);
4486 else if (r_refdef.scene.worldentity->model)
4487 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);
4489 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4492 static void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
4494 qboolean zpass = false;
4497 int surfacelistindex;
4498 msurface_t *surface;
4500 // if triangle neighbors are disabled, shadowvolumes are disabled
4501 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
4504 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4506 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4509 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
4511 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
4512 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
4514 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
4515 for (;mesh;mesh = mesh->next)
4517 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->numtriangles;
4518 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4519 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
4521 // increment stencil if frontface is infront of depthbuffer
4522 GL_CullFace(r_refdef.view.cullface_back);
4523 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
4524 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);
4525 // decrement stencil if backface is infront of depthbuffer
4526 GL_CullFace(r_refdef.view.cullface_front);
4527 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
4529 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
4531 // decrement stencil if backface is behind depthbuffer
4532 GL_CullFace(r_refdef.view.cullface_front);
4533 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
4534 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);
4535 // increment stencil if frontface is behind depthbuffer
4536 GL_CullFace(r_refdef.view.cullface_back);
4537 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
4539 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);
4543 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
4545 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
4546 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
4547 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
4549 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
4550 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
4551 if (CHECKPVSBIT(trispvs, t))
4552 shadowmarklist[numshadowmark++] = t;
4554 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);
4556 else if (numsurfaces)
4558 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);
4561 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4564 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
4566 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
4567 vec_t relativeshadowradius;
4568 RSurf_ActiveModelEntity(ent, false, false, false);
4569 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
4570 // we need to re-init the shader for each entity because the matrix changed
4571 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
4572 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
4573 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
4574 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
4575 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
4576 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
4577 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
4578 switch (r_shadow_rendermode)
4580 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
4581 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4584 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4587 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4590 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
4592 // set up properties for rendering light onto this entity
4593 RSurf_ActiveModelEntity(ent, true, true, false);
4594 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
4595 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4596 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4597 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4600 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
4602 if (!r_refdef.scene.worldmodel->DrawLight)
4605 // set up properties for rendering light onto this entity
4606 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4607 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
4608 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4609 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4610 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4612 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
4614 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4617 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
4619 dp_model_t *model = ent->model;
4620 if (!model->DrawLight)
4623 R_Shadow_SetupEntityLight(ent);
4625 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
4627 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4630 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
4634 int numleafs, numsurfaces;
4635 int *leaflist, *surfacelist;
4636 unsigned char *leafpvs;
4637 unsigned char *shadowtrispvs;
4638 unsigned char *lighttrispvs;
4639 //unsigned char *surfacesides;
4640 int numlightentities;
4641 int numlightentities_noselfshadow;
4642 int numshadowentities;
4643 int numshadowentities_noselfshadow;
4644 // FIXME: bounds check lightentities and shadowentities, etc.
4645 static entity_render_t *lightentities[MAX_EDICTS];
4646 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
4647 static entity_render_t *shadowentities[MAX_EDICTS];
4648 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
4650 qboolean castshadows;
4652 rtlight->draw = false;
4653 rtlight->cached_numlightentities = 0;
4654 rtlight->cached_numlightentities_noselfshadow = 0;
4655 rtlight->cached_numshadowentities = 0;
4656 rtlight->cached_numshadowentities_noselfshadow = 0;
4657 rtlight->cached_numsurfaces = 0;
4658 rtlight->cached_lightentities = NULL;
4659 rtlight->cached_lightentities_noselfshadow = NULL;
4660 rtlight->cached_shadowentities = NULL;
4661 rtlight->cached_shadowentities_noselfshadow = NULL;
4662 rtlight->cached_shadowtrispvs = NULL;
4663 rtlight->cached_lighttrispvs = NULL;
4664 rtlight->cached_surfacelist = NULL;
4665 rtlight->shadowmapsidesize = 0;
4667 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
4668 // skip lights that are basically invisible (color 0 0 0)
4669 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
4671 // loading is done before visibility checks because loading should happen
4672 // all at once at the start of a level, not when it stalls gameplay.
4673 // (especially important to benchmarks)
4675 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
4677 if (rtlight->compiled)
4678 R_RTLight_Uncompile(rtlight);
4679 R_RTLight_Compile(rtlight);
4683 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
4685 // look up the light style value at this time
4686 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4687 VectorScale(rtlight->color, f, rtlight->currentcolor);
4689 if (rtlight->selected)
4691 f = 2 + sin(realtime * M_PI * 4.0);
4692 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
4696 // skip if lightstyle is currently off
4697 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
4700 // skip processing on corona-only lights
4704 // skip if the light box is not touching any visible leafs
4705 if (r_shadow_culllights_pvs.integer
4706 && r_refdef.scene.worldmodel
4707 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
4708 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, rtlight->cullmins, rtlight->cullmaxs))
4711 // skip if the light box is not visible to traceline
4712 if (r_shadow_culllights_trace.integer)
4714 if (rtlight->trace_timer != realtime && R_CanSeeBox(rtlight->trace_timer == 0 ? r_shadow_culllights_trace_tempsamples.integer : r_shadow_culllights_trace_samples.integer, r_shadow_culllights_trace_eyejitter.value, r_shadow_culllights_trace_enlarge.value, r_shadow_culllights_trace_expand.value, r_shadow_culllights_trace_pad.value, r_refdef.view.origin, rtlight->cullmins, rtlight->cullmaxs))
4715 rtlight->trace_timer = realtime;
4716 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
4720 // skip if the light box is off screen
4721 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
4724 // in the typical case this will be quickly replaced by GetLightInfo
4725 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
4726 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
4728 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4730 // 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
4731 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
4734 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
4736 // compiled light, world available and can receive realtime lighting
4737 // retrieve leaf information
4738 numleafs = rtlight->static_numleafs;
4739 leaflist = rtlight->static_leaflist;
4740 leafpvs = rtlight->static_leafpvs;
4741 numsurfaces = rtlight->static_numsurfaces;
4742 surfacelist = rtlight->static_surfacelist;
4743 //surfacesides = NULL;
4744 shadowtrispvs = rtlight->static_shadowtrispvs;
4745 lighttrispvs = rtlight->static_lighttrispvs;
4747 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4749 // dynamic light, world available and can receive realtime lighting
4750 // calculate lit surfaces and leafs
4751 r_refdef.scene.worldmodel->GetLightInfo(r_refdef.scene.worldentity, rtlight->shadoworigin, rtlight->radius, rtlight->cached_cullmins, rtlight->cached_cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes, rtlight->shadow == 0);
4752 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4753 leaflist = r_shadow_buffer_leaflist;
4754 leafpvs = r_shadow_buffer_leafpvs;
4755 surfacelist = r_shadow_buffer_surfacelist;
4756 //surfacesides = r_shadow_buffer_surfacesides;
4757 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4758 lighttrispvs = r_shadow_buffer_lighttrispvs;
4759 // if the reduced leaf bounds are offscreen, skip it
4760 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4771 //surfacesides = NULL;
4772 shadowtrispvs = NULL;
4773 lighttrispvs = NULL;
4775 // check if light is illuminating any visible leafs
4778 for (i = 0; i < numleafs; i++)
4779 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4785 // make a list of lit entities and shadow casting entities
4786 numlightentities = 0;
4787 numlightentities_noselfshadow = 0;
4788 numshadowentities = 0;
4789 numshadowentities_noselfshadow = 0;
4791 // add dynamic entities that are lit by the light
4792 for (i = 0; i < r_refdef.scene.numentities; i++)
4795 entity_render_t *ent = r_refdef.scene.entities[i];
4797 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4799 // skip the object entirely if it is not within the valid
4800 // shadow-casting region (which includes the lit region)
4801 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
4803 if (!(model = ent->model))
4805 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4807 // this entity wants to receive light, is visible, and is
4808 // inside the light box
4809 // TODO: check if the surfaces in the model can receive light
4810 // so now check if it's in a leaf seen by the light
4811 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))
4813 if (ent->flags & RENDER_NOSELFSHADOW)
4814 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
4816 lightentities[numlightentities++] = ent;
4817 // since it is lit, it probably also casts a shadow...
4818 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4819 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4820 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4822 // note: exterior models without the RENDER_NOSELFSHADOW
4823 // flag still create a RENDER_NOSELFSHADOW shadow but
4824 // are lit normally, this means that they are
4825 // self-shadowing but do not shadow other
4826 // RENDER_NOSELFSHADOW entities such as the gun
4827 // (very weird, but keeps the player shadow off the gun)
4828 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4829 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4831 shadowentities[numshadowentities++] = ent;
4834 else if (ent->flags & RENDER_SHADOW)
4836 // this entity is not receiving light, but may still need to
4838 // TODO: check if the surfaces in the model can cast shadow
4839 // now check if it is in a leaf seen by the light
4840 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))
4842 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4843 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4844 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4846 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4847 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4849 shadowentities[numshadowentities++] = ent;
4854 // return if there's nothing at all to light
4855 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4858 // count this light in the r_speeds
4859 r_refdef.stats[r_stat_lights]++;
4861 // flag it as worth drawing later
4862 rtlight->draw = true;
4864 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
4865 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4867 numshadowentities = numshadowentities_noselfshadow = 0;
4868 rtlight->castshadows = castshadows;
4870 // cache all the animated entities that cast a shadow but are not visible
4871 for (i = 0; i < numshadowentities; i++)
4872 R_AnimCache_GetEntity(shadowentities[i], false, false);
4873 for (i = 0; i < numshadowentities_noselfshadow; i++)
4874 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4876 // 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)
4877 if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
4879 for (i = 0; i < numshadowentities_noselfshadow; i++)
4880 shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
4881 numshadowentities_noselfshadow = 0;
4884 // we can convert noselfshadow to regular if there are no casters of that type
4885 if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
4887 for (i = 0; i < numlightentities_noselfshadow; i++)
4888 lightentities[numlightentities++] = lightentities_noselfshadow[i];
4889 numlightentities_noselfshadow = 0;
4892 // allocate some temporary memory for rendering this light later in the frame
4893 // reusable buffers need to be copied, static data can be used as-is
4894 rtlight->cached_numlightentities = numlightentities;
4895 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
4896 rtlight->cached_numshadowentities = numshadowentities;
4897 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4898 rtlight->cached_numsurfaces = numsurfaces;
4899 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4900 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4901 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4902 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4903 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4905 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4906 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4907 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4908 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4909 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4913 // compiled light data
4914 rtlight->cached_shadowtrispvs = shadowtrispvs;
4915 rtlight->cached_lighttrispvs = lighttrispvs;
4916 rtlight->cached_surfacelist = surfacelist;
4919 if (R_Shadow_ShadowMappingEnabled())
4921 // figure out the shadowmapping parameters for this light
4922 vec3_t nearestpoint;
4925 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4926 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4927 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4928 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4929 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
4930 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4931 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4932 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4933 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
4937 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
4941 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4942 int numlightentities;
4943 int numlightentities_noselfshadow;
4944 int numshadowentities;
4945 int numshadowentities_noselfshadow;
4946 entity_render_t **lightentities;
4947 entity_render_t **lightentities_noselfshadow;
4948 entity_render_t **shadowentities;
4949 entity_render_t **shadowentities_noselfshadow;
4951 static unsigned char entitysides[MAX_EDICTS];
4952 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4958 matrix4x4_t radiustolight;
4960 // check if we cached this light this frame (meaning it is worth drawing)
4961 if (!rtlight->draw || !rtlight->castshadows)
4964 // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
4965 if (rtlight->shadowmapatlassidesize == 0)
4967 rtlight->castshadows = false;
4971 // set up a scissor rectangle for this light
4972 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4975 // don't let sound skip if going slow
4976 if (r_refdef.scene.extraupdate)
4979 numlightentities = rtlight->cached_numlightentities;
4980 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4981 numshadowentities = rtlight->cached_numshadowentities;
4982 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4983 numsurfaces = rtlight->cached_numsurfaces;
4984 lightentities = rtlight->cached_lightentities;
4985 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4986 shadowentities = rtlight->cached_shadowentities;
4987 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4988 shadowtrispvs = rtlight->cached_shadowtrispvs;
4989 lighttrispvs = rtlight->cached_lighttrispvs;
4990 surfacelist = rtlight->cached_surfacelist;
4992 // make this the active rtlight for rendering purposes
4993 R_Shadow_RenderMode_ActiveLight(rtlight);
4995 radiustolight = rtlight->matrix_worldtolight;
4996 Matrix4x4_Abs(&radiustolight);
4998 size = rtlight->shadowmapatlassidesize;
4999 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
5001 surfacesides = NULL;
5006 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
5008 castermask = rtlight->static_shadowmap_casters;
5009 receivermask = rtlight->static_shadowmap_receivers;
5013 surfacesides = r_shadow_buffer_surfacesides;
5014 for (i = 0; i < numsurfaces; i++)
5016 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
5017 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
5018 castermask |= surfacesides[i];
5019 receivermask |= surfacesides[i];
5024 for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
5025 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
5026 for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
5027 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
5029 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
5033 for (i = 0; i < numshadowentities; i++)
5034 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
5035 for (i = 0; i < numshadowentities_noselfshadow; i++)
5036 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
5039 // there is no need to render shadows for sides that have no receivers...
5040 castermask &= receivermask;
5042 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
5044 // render shadow casters into shadowmaps for this light
5045 for (side = 0; side < 6; side++)
5047 int bit = 1 << side;
5048 if (castermask & bit)
5050 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
5052 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
5053 for (i = 0; i < numshadowentities; i++)
5054 if (entitysides[i] & bit)
5055 R_Shadow_DrawEntityShadow(shadowentities[i]);
5056 for (i = 0; i < numshadowentities_noselfshadow; i++)
5057 if (entitysides_noselfshadow[i] & bit)
5058 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5061 // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
5062 if (numshadowentities_noselfshadow)
5064 for (side = 0; side < 6; side++)
5066 int bit = 1 << side;
5067 if (castermask & bit)
5069 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
5071 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
5072 for (i = 0; i < numshadowentities; i++)
5073 if (entitysides[i] & bit)
5074 R_Shadow_DrawEntityShadow(shadowentities[i]);
5080 static void R_Shadow_DrawLight(rtlight_t *rtlight)
5084 unsigned char *shadowtrispvs, *lighttrispvs;
5085 int numlightentities;
5086 int numlightentities_noselfshadow;
5087 int numshadowentities;
5088 int numshadowentities_noselfshadow;
5089 entity_render_t **lightentities;
5090 entity_render_t **lightentities_noselfshadow;
5091 entity_render_t **shadowentities;
5092 entity_render_t **shadowentities_noselfshadow;
5094 qboolean castshadows;
5096 // check if we cached this light this frame (meaning it is worth drawing)
5100 // set up a scissor rectangle for this light
5101 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
5104 // don't let sound skip if going slow
5105 if (r_refdef.scene.extraupdate)
5108 numlightentities = rtlight->cached_numlightentities;
5109 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
5110 numshadowentities = rtlight->cached_numshadowentities;
5111 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
5112 numsurfaces = rtlight->cached_numsurfaces;
5113 lightentities = rtlight->cached_lightentities;
5114 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
5115 shadowentities = rtlight->cached_shadowentities;
5116 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
5117 shadowtrispvs = rtlight->cached_shadowtrispvs;
5118 lighttrispvs = rtlight->cached_lighttrispvs;
5119 surfacelist = rtlight->cached_surfacelist;
5120 castshadows = rtlight->castshadows;
5122 // make this the active rtlight for rendering purposes
5123 R_Shadow_RenderMode_ActiveLight(rtlight);
5125 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
5127 // optionally draw visible shape of the shadow volumes
5128 // for performance analysis by level designers
5129 R_Shadow_RenderMode_VisibleShadowVolumes();
5131 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
5132 for (i = 0;i < numshadowentities;i++)
5133 R_Shadow_DrawEntityShadow(shadowentities[i]);
5134 for (i = 0;i < numshadowentities_noselfshadow;i++)
5135 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5136 R_Shadow_RenderMode_VisibleLighting(false, false);
5139 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
5141 // optionally draw the illuminated areas
5142 // for performance analysis by level designers
5143 R_Shadow_RenderMode_VisibleLighting(false, false);
5145 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5146 for (i = 0;i < numlightentities;i++)
5147 R_Shadow_DrawEntityLight(lightentities[i]);
5148 for (i = 0;i < numlightentities_noselfshadow;i++)
5149 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5152 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
5156 float shadowmapoffsetnoselfshadow = 0;
5157 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
5158 Matrix4x4_Abs(&radiustolight);
5160 size = rtlight->shadowmapatlassidesize;
5161 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
5163 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
5165 if (rtlight->cached_numshadowentities_noselfshadow)
5166 shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
5168 // render lighting using the depth texture as shadowmap
5169 // draw lighting in the unmasked areas
5170 if (numsurfaces + numlightentities)
5172 R_Shadow_RenderMode_Lighting(false, false, true, false);
5173 // draw lighting in the unmasked areas
5175 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5176 for (i = 0; i < numlightentities; i++)
5177 R_Shadow_DrawEntityLight(lightentities[i]);
5179 // offset to the noselfshadow part of the atlas and draw those too
5180 if (numlightentities_noselfshadow)
5182 R_Shadow_RenderMode_Lighting(false, false, true, true);
5183 for (i = 0; i < numlightentities_noselfshadow; i++)
5184 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5187 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5188 if (r_shadow_usingdeferredprepass)
5189 R_Shadow_RenderMode_DrawDeferredLight(true);
5191 else if (castshadows && vid.stencil)
5193 // draw stencil shadow volumes to mask off pixels that are in shadow
5194 // so that they won't receive lighting
5195 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
5196 R_Shadow_ClearStencil();
5199 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
5200 for (i = 0;i < numshadowentities;i++)
5201 R_Shadow_DrawEntityShadow(shadowentities[i]);
5203 // draw lighting in the unmasked areas
5204 R_Shadow_RenderMode_Lighting(true, false, false, false);
5205 for (i = 0;i < numlightentities_noselfshadow;i++)
5206 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5208 for (i = 0;i < numshadowentities_noselfshadow;i++)
5209 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
5211 // draw lighting in the unmasked areas
5212 R_Shadow_RenderMode_Lighting(true, false, false, false);
5214 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5215 for (i = 0;i < numlightentities;i++)
5216 R_Shadow_DrawEntityLight(lightentities[i]);
5218 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5219 if (r_shadow_usingdeferredprepass)
5220 R_Shadow_RenderMode_DrawDeferredLight(false);
5224 // draw lighting in the unmasked areas
5225 R_Shadow_RenderMode_Lighting(false, false, false, false);
5227 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
5228 for (i = 0;i < numlightentities;i++)
5229 R_Shadow_DrawEntityLight(lightentities[i]);
5230 for (i = 0;i < numlightentities_noselfshadow;i++)
5231 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
5233 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
5234 if (r_shadow_usingdeferredprepass)
5235 R_Shadow_RenderMode_DrawDeferredLight(false);
5239 static void R_Shadow_FreeDeferred(void)
5241 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
5242 r_shadow_prepassgeometryfbo = 0;
5244 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
5245 r_shadow_prepasslightingdiffusespecularfbo = 0;
5247 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
5248 r_shadow_prepasslightingdiffusefbo = 0;
5250 if (r_shadow_prepassgeometrydepthbuffer)
5251 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
5252 r_shadow_prepassgeometrydepthbuffer = NULL;
5254 if (r_shadow_prepassgeometrynormalmaptexture)
5255 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
5256 r_shadow_prepassgeometrynormalmaptexture = NULL;
5258 if (r_shadow_prepasslightingdiffusetexture)
5259 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
5260 r_shadow_prepasslightingdiffusetexture = NULL;
5262 if (r_shadow_prepasslightingspeculartexture)
5263 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
5264 r_shadow_prepasslightingspeculartexture = NULL;
5267 void R_Shadow_DrawPrepass(void)
5271 entity_render_t *ent;
5272 float clearcolor[4];
5274 R_Mesh_ResetTextureState();
5276 GL_ColorMask(1,1,1,1);
5277 GL_BlendFunc(GL_ONE, GL_ZERO);
5280 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5281 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
5282 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
5283 if (r_timereport_active)
5284 R_TimeReport("prepasscleargeom");
5286 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
5287 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
5288 if (r_timereport_active)
5289 R_TimeReport("prepassworld");
5291 for (i = 0;i < r_refdef.scene.numentities;i++)
5293 if (!r_refdef.viewcache.entityvisible[i])
5295 ent = r_refdef.scene.entities[i];
5296 if (ent->model && ent->model->DrawPrepass != NULL)
5297 ent->model->DrawPrepass(ent);
5300 if (r_timereport_active)
5301 R_TimeReport("prepassmodels");
5303 GL_DepthMask(false);
5304 GL_ColorMask(1,1,1,1);
5307 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5308 Vector4Set(clearcolor, 0, 0, 0, 0);
5309 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
5310 if (r_timereport_active)
5311 R_TimeReport("prepassclearlit");
5313 R_Shadow_RenderMode_Begin();
5315 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5316 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5318 R_Shadow_RenderMode_End();
5320 if (r_timereport_active)
5321 R_TimeReport("prepasslights");
5324 #define MAX_SCENELIGHTS 65536
5325 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
5327 if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
5329 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
5331 r_shadow_scenemaxlights *= 2;
5332 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
5333 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
5335 r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
5339 void R_Shadow_DrawLightSprites(void);
5340 void R_Shadow_PrepareLights(void)
5349 int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
5350 int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
5351 int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
5353 if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
5354 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
5355 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
5356 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
5357 r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) ||
5358 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
5359 r_shadow_shadowmapborder != shadowmapborder ||
5360 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
5361 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
5362 R_Shadow_FreeShadowMaps();
5364 r_shadow_usingshadowmaportho = false;
5366 switch (vid.renderpath)
5368 case RENDERPATH_GL20:
5369 case RENDERPATH_D3D9:
5370 case RENDERPATH_D3D10:
5371 case RENDERPATH_D3D11:
5372 case RENDERPATH_SOFT:
5374 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
5376 r_shadow_usingdeferredprepass = false;
5377 if (r_shadow_prepass_width)
5378 R_Shadow_FreeDeferred();
5379 r_shadow_prepass_width = r_shadow_prepass_height = 0;
5383 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
5385 R_Shadow_FreeDeferred();
5387 r_shadow_usingdeferredprepass = true;
5388 r_shadow_prepass_width = vid.width;
5389 r_shadow_prepass_height = vid.height;
5390 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
5391 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);
5392 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);
5393 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);
5395 // set up the geometry pass fbo (depth + normalmap)
5396 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5397 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
5398 // render depth into a renderbuffer and other important properties into the normalmap texture
5400 // set up the lighting pass fbo (diffuse + specular)
5401 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5402 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
5403 // render diffuse into one texture and specular into another,
5404 // with depth and normalmap bound as textures,
5405 // with depth bound as attachment as well
5407 // set up the lighting pass fbo (diffuse)
5408 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5409 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
5410 // render diffuse into one texture,
5411 // with depth and normalmap bound as textures,
5412 // with depth bound as attachment as well
5416 case RENDERPATH_GL11:
5417 case RENDERPATH_GL13:
5418 case RENDERPATH_GLES1:
5419 case RENDERPATH_GLES2:
5420 r_shadow_usingdeferredprepass = false;
5424 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);
5426 r_shadow_scenenumlights = 0;
5427 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5428 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5429 for (lightindex = 0; lightindex < range; lightindex++)
5431 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5432 if (light && (light->flags & flag))
5434 R_Shadow_PrepareLight(&light->rtlight);
5435 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5438 if (r_refdef.scene.rtdlight)
5440 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5442 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
5443 R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
5446 else if (gl_flashblend.integer)
5448 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
5450 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
5451 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
5452 VectorScale(rtlight->color, f, rtlight->currentcolor);
5456 // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
5457 if (r_shadow_debuglight.integer >= 0)
5459 r_shadow_scenenumlights = 0;
5460 lightindex = r_shadow_debuglight.integer;
5461 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5464 R_Shadow_PrepareLight(&light->rtlight);
5465 R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
5469 // if we're doing shadowmaps we need to prepare the atlas layout now
5470 if (R_Shadow_ShadowMappingEnabled())
5474 // allocate shadowmaps in the atlas now
5475 // 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...
5476 for (lod = 0; lod < 16; lod++)
5478 int packing_success = 0;
5479 int packing_failure = 0;
5480 Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
5481 // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
5482 if (r_shadow_shadowmapatlas_modelshadows_size)
5483 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);
5484 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5486 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
5487 int size = rtlight->shadowmapsidesize >> lod;
5489 if (!rtlight->castshadows)
5491 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
5494 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
5495 if (rtlight->cached_numshadowentities_noselfshadow)
5497 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
5499 rtlight->shadowmapatlassidesize = size;
5504 // note down that we failed to pack this one, it will have to disable shadows
5505 rtlight->shadowmapatlassidesize = 0;
5509 // generally everything fits and we stop here on the first iteration
5510 if (packing_failure == 0)
5515 if (r_editlights.integer)
5516 R_Shadow_DrawLightSprites();
5519 void R_Shadow_DrawShadowMaps(void)
5521 R_Shadow_RenderMode_Begin();
5522 R_Shadow_RenderMode_ActiveLight(NULL);
5524 // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
5525 R_Shadow_ClearShadowMapTexture();
5527 // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
5528 if (r_shadow_shadowmapatlas_modelshadows_size)
5530 R_Shadow_DrawModelShadowMaps();
5531 // don't let sound skip if going slow
5532 if (r_refdef.scene.extraupdate)
5536 if (R_Shadow_ShadowMappingEnabled())
5539 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5540 R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
5543 R_Shadow_RenderMode_End();
5546 void R_Shadow_DrawLights(void)
5550 R_Shadow_RenderMode_Begin();
5552 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
5553 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
5555 R_Shadow_RenderMode_End();
5558 #define MAX_MODELSHADOWS 1024
5559 static int r_shadow_nummodelshadows;
5560 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
5562 void R_Shadow_PrepareModelShadows(void)
5565 float scale, size, radius, dot1, dot2;
5566 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5567 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
5568 entity_render_t *ent;
5570 r_shadow_nummodelshadows = 0;
5571 r_shadow_shadowmapatlas_modelshadows_size = 0;
5573 if (!r_refdef.scene.numentities || r_refdef.scene.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
5576 switch (r_shadow_shadowmode)
5578 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
5579 if (r_shadows.integer >= 2)
5582 case R_SHADOW_SHADOWMODE_STENCIL:
5585 for (i = 0; i < r_refdef.scene.numentities; i++)
5587 ent = r_refdef.scene.entities[i];
5588 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5590 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5592 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5593 R_AnimCache_GetEntity(ent, false, false);
5601 size = r_shadow_shadowmaptexturesize / 4;
5602 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
5603 radius = 0.5f * size / scale;
5605 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5606 VectorCopy(prvmshadowdir, shadowdir);
5607 VectorNormalize(shadowdir);
5608 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5609 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5610 if (fabs(dot1) <= fabs(dot2))
5611 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5613 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5614 VectorNormalize(shadowforward);
5615 CrossProduct(shadowdir, shadowforward, shadowright);
5616 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5617 VectorCopy(prvmshadowfocus, shadowfocus);
5618 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5619 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5620 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5621 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5622 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5624 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5626 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5627 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5628 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5629 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5630 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5631 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5633 for (i = 0; i < r_refdef.scene.numentities; i++)
5635 ent = r_refdef.scene.entities[i];
5636 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
5638 // cast shadows from anything of the map (submodels are optional)
5639 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5641 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5643 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5644 R_AnimCache_GetEntity(ent, false, false);
5648 if (r_shadow_nummodelshadows)
5650 r_shadow_shadowmapatlas_modelshadows_x = 0;
5651 r_shadow_shadowmapatlas_modelshadows_y = 0;
5652 r_shadow_shadowmapatlas_modelshadows_size = size;
5656 static void R_Shadow_DrawModelShadowMaps(void)
5659 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
5660 entity_render_t *ent;
5661 vec3_t relativelightorigin;
5662 vec3_t relativelightdirection, relativeforward, relativeright;
5663 vec3_t relativeshadowmins, relativeshadowmaxs;
5664 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
5665 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5667 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
5668 r_viewport_t viewport;
5670 size = r_shadow_shadowmapatlas_modelshadows_size;
5671 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
5672 radius = 0.5f / scale;
5673 nearclip = -r_shadows_throwdistance.value;
5674 farclip = r_shadows_throwdistance.value;
5675 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);
5677 // set the parameters that will be used on the regular model renders using these shadows we're about to produce
5678 r_shadow_modelshadowmap_parameters[0] = size;
5679 r_shadow_modelshadowmap_parameters[1] = size;
5680 r_shadow_modelshadowmap_parameters[2] = 1.0;
5681 r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
5682 r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
5683 r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
5684 r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
5685 r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
5686 r_shadow_usingshadowmaportho = true;
5688 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5689 VectorCopy(prvmshadowdir, shadowdir);
5690 VectorNormalize(shadowdir);
5691 Math_atov(r_shadows_focus.string, prvmshadowfocus);
5692 VectorCopy(prvmshadowfocus, shadowfocus);
5693 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5694 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5695 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5696 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5697 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5698 dot2 = DotProduct(r_refdef.view.up, shadowdir);
5699 if (fabs(dot1) <= fabs(dot2))
5700 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5702 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5703 VectorNormalize(shadowforward);
5704 VectorM(scale, shadowforward, &m[0]);
5705 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5707 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
5708 CrossProduct(shadowdir, shadowforward, shadowright);
5709 VectorM(scale, shadowright, &m[4]);
5710 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
5711 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
5712 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
5713 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
5714 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
5715 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);
5716 R_SetViewport(&viewport);
5718 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5720 // render into a slightly restricted region so that the borders of the
5721 // shadowmap area fade away, rather than streaking across everything
5722 // outside the usable area
5723 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
5725 for (i = 0;i < r_shadow_nummodelshadows;i++)
5727 ent = r_shadow_modelshadows[i];
5728 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5729 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
5730 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5731 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
5732 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
5733 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5734 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5735 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5736 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5737 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5738 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5739 RSurf_ActiveModelEntity(ent, false, false, false);
5740 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
5741 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5747 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
5749 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
5751 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
5752 Cvar_SetValueQuick(&r_test, 0);
5757 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
5758 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
5759 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
5760 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
5761 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
5762 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
5764 switch (vid.renderpath)
5766 case RENDERPATH_GL11:
5767 case RENDERPATH_GL13:
5768 case RENDERPATH_GL20:
5769 case RENDERPATH_SOFT:
5770 case RENDERPATH_GLES1:
5771 case RENDERPATH_GLES2:
5773 case RENDERPATH_D3D9:
5774 case RENDERPATH_D3D10:
5775 case RENDERPATH_D3D11:
5776 #ifdef MATRIX4x4_OPENGLORIENTATION
5777 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5778 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
5779 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
5780 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
5782 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
5783 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
5784 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
5785 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
5791 void R_Shadow_DrawModelShadows(void)
5794 float relativethrowdistance;
5795 entity_render_t *ent;
5796 vec3_t relativelightorigin;
5797 vec3_t relativelightdirection;
5798 vec3_t relativeshadowmins, relativeshadowmaxs;
5799 vec3_t tmp, shadowdir;
5800 prvm_vec3_t prvmshadowdir;
5802 if (!r_shadow_nummodelshadows || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
5805 R_ResetViewRendering3D(r_shadow_viewfbo, r_shadow_viewdepthtexture, r_shadow_viewcolortexture, r_shadow_viewx, r_shadow_viewy, r_shadow_viewwidth, r_shadow_viewheight);
5806 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
5807 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5808 R_Shadow_RenderMode_Begin();
5809 R_Shadow_RenderMode_ActiveLight(NULL);
5810 r_shadow_lightscissor[0] = r_shadow_viewx;
5811 r_shadow_lightscissor[1] = (r_shadow_viewfbo ? r_shadow_viewheight : vid.height) - r_shadow_viewy - r_shadow_viewheight;
5812 r_shadow_lightscissor[2] = r_shadow_viewwidth;
5813 r_shadow_lightscissor[3] = r_shadow_viewheight;
5814 R_Shadow_RenderMode_StencilShadowVolumes(false);
5817 if (r_shadows.integer == 2)
5819 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5820 VectorCopy(prvmshadowdir, shadowdir);
5821 VectorNormalize(shadowdir);
5824 R_Shadow_ClearStencil();
5826 for (i = 0;i < r_shadow_nummodelshadows;i++)
5828 ent = r_shadow_modelshadows[i];
5830 // cast shadows from anything of the map (submodels are optional)
5831 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5832 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
5833 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
5834 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
5835 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5838 VectorNegate(ent->render_modellight_lightdir, tmp);
5839 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
5842 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
5843 RSurf_ActiveModelEntity(ent, false, false, false);
5844 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
5845 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5848 // not really the right mode, but this will disable any silly stencil features
5849 R_Shadow_RenderMode_End();
5851 // set up ortho view for rendering this pass
5852 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5853 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5854 //GL_ScissorTest(true);
5855 //R_EntityMatrix(&identitymatrix);
5856 //R_Mesh_ResetTextureState();
5857 R_ResetViewRendering2D(r_shadow_viewfbo, r_shadow_viewdepthtexture, r_shadow_viewcolortexture, r_shadow_viewx, r_shadow_viewy, r_shadow_viewwidth, r_shadow_viewheight);
5859 // set up a darkening blend on shadowed areas
5860 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5861 //GL_DepthRange(0, 1);
5862 //GL_DepthTest(false);
5863 //GL_DepthMask(false);
5864 //GL_PolygonOffset(0, 0);CHECKGLERROR
5865 GL_Color(0, 0, 0, r_shadows_darken.value);
5866 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5867 //GL_DepthFunc(GL_ALWAYS);
5868 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5870 // apply the blend to the shadowed areas
5871 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5872 R_SetupShader_Generic_NoTexture(false, true);
5873 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5875 // restore the viewport
5876 R_SetViewport(&r_refdef.view.viewport);
5878 // restore other state to normal
5879 //R_Shadow_RenderMode_End();
5882 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5885 vec3_t centerorigin;
5886 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5889 // if it's too close, skip it
5890 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5892 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5895 if (usequery && r_numqueries + 2 <= r_maxqueries)
5897 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5898 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5899 // 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
5900 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5902 switch(vid.renderpath)
5904 case RENDERPATH_GL11:
5905 case RENDERPATH_GL13:
5906 case RENDERPATH_GL20:
5907 case RENDERPATH_GLES1:
5908 case RENDERPATH_GLES2:
5909 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5911 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5912 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5913 GL_DepthFunc(GL_ALWAYS);
5914 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5915 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5916 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5917 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5918 GL_DepthFunc(GL_LEQUAL);
5919 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5920 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5921 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5922 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5923 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5927 case RENDERPATH_D3D9:
5928 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5930 case RENDERPATH_D3D10:
5931 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5933 case RENDERPATH_D3D11:
5934 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5936 case RENDERPATH_SOFT:
5937 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5941 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5944 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5946 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5949 unsigned int occlude = 0;
5950 GLint allpixels = 0, visiblepixels = 0;
5952 // now we have to check the query result
5953 if (rtlight->corona_queryindex_visiblepixels)
5955 switch(vid.renderpath)
5957 case RENDERPATH_GL20:
5958 case RENDERPATH_GLES1:
5959 case RENDERPATH_GLES2:
5960 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5961 // See if we can use the GPU-side method to prevent implicit sync
5962 if (vid.support.arb_query_buffer_object) {
5963 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
5964 if (!r_shadow_occlusion_buf) {
5965 qglGenBuffersARB(1, &r_shadow_occlusion_buf);
5966 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5967 qglBufferDataARB(GL_QUERY_BUFFER_ARB, 8, NULL, GL_DYNAMIC_COPY);
5969 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5971 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(0));
5972 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4));
5973 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
5974 occlude = MATERIALFLAG_OCCLUDE;
5975 cscale *= rtlight->corona_visibility;
5983 case RENDERPATH_GL11:
5984 case RENDERPATH_GL13:
5985 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5987 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5988 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5989 if (visiblepixels < 1 || allpixels < 1)
5991 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5992 cscale *= rtlight->corona_visibility;
5998 case RENDERPATH_D3D9:
5999 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6001 case RENDERPATH_D3D10:
6002 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6004 case RENDERPATH_D3D11:
6005 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6007 case RENDERPATH_SOFT:
6008 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6016 if (CL_Cache_TraceLineSurfaces(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT).fraction < 1)
6019 VectorScale(rtlight->currentcolor, cscale, color);
6020 if (VectorLength(color) > (1.0f / 256.0f))
6023 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
6026 VectorNegate(color, color);
6027 GL_BlendEquationSubtract(true);
6029 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
6030 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);
6031 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
6033 GL_BlendEquationSubtract(false);
6037 void R_Shadow_DrawCoronas(void)
6040 qboolean usequery = false;
6045 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
6047 if (r_fb.water.renderingscene)
6049 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6050 R_EntityMatrix(&identitymatrix);
6052 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6054 // check occlusion of coronas
6055 // use GL_ARB_occlusion_query if available
6056 // otherwise use raytraces
6058 switch (vid.renderpath)
6060 case RENDERPATH_GL11:
6061 case RENDERPATH_GL13:
6062 case RENDERPATH_GL20:
6063 case RENDERPATH_GLES1:
6064 case RENDERPATH_GLES2:
6065 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
6066 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
6069 GL_ColorMask(0,0,0,0);
6070 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
6071 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
6074 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
6075 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
6077 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
6080 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6081 GL_BlendFunc(GL_ONE, GL_ZERO);
6082 GL_CullFace(GL_NONE);
6083 GL_DepthMask(false);
6084 GL_DepthRange(0, 1);
6085 GL_PolygonOffset(0, 0);
6087 R_Mesh_ResetTextureState();
6088 R_SetupShader_Generic_NoTexture(false, false);
6092 case RENDERPATH_D3D9:
6094 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6096 case RENDERPATH_D3D10:
6097 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6099 case RENDERPATH_D3D11:
6100 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6102 case RENDERPATH_SOFT:
6104 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
6107 for (lightindex = 0;lightindex < range;lightindex++)
6109 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6112 rtlight = &light->rtlight;
6113 rtlight->corona_visibility = 0;
6114 rtlight->corona_queryindex_visiblepixels = 0;
6115 rtlight->corona_queryindex_allpixels = 0;
6116 if (!(rtlight->flags & flag))
6118 if (rtlight->corona <= 0)
6120 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
6122 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6124 for (i = 0;i < r_refdef.scene.numlights;i++)
6126 rtlight = r_refdef.scene.lights[i];
6127 rtlight->corona_visibility = 0;
6128 rtlight->corona_queryindex_visiblepixels = 0;
6129 rtlight->corona_queryindex_allpixels = 0;
6130 if (!(rtlight->flags & flag))
6132 if (rtlight->corona <= 0)
6134 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
6137 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
6139 // now draw the coronas using the query data for intensity info
6140 for (lightindex = 0;lightindex < range;lightindex++)
6142 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6145 rtlight = &light->rtlight;
6146 if (rtlight->corona_visibility <= 0)
6148 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6150 for (i = 0;i < r_refdef.scene.numlights;i++)
6152 rtlight = r_refdef.scene.lights[i];
6153 if (rtlight->corona_visibility <= 0)
6155 if (gl_flashblend.integer)
6156 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
6158 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
6164 static dlight_t *R_Shadow_NewWorldLight(void)
6166 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
6169 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)
6173 // 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
6175 // validate parameters
6179 // copy to light properties
6180 VectorCopy(origin, light->origin);
6181 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
6182 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
6183 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
6185 light->color[0] = max(color[0], 0);
6186 light->color[1] = max(color[1], 0);
6187 light->color[2] = max(color[2], 0);
6189 light->color[0] = color[0];
6190 light->color[1] = color[1];
6191 light->color[2] = color[2];
6192 light->radius = max(radius, 0);
6193 light->style = style;
6194 light->shadow = shadowenable;
6195 light->corona = corona;
6196 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
6197 light->coronasizescale = coronasizescale;
6198 light->ambientscale = ambientscale;
6199 light->diffusescale = diffusescale;
6200 light->specularscale = specularscale;
6201 light->flags = flags;
6203 // update renderable light data
6204 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
6205 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);
6208 static void R_Shadow_FreeWorldLight(dlight_t *light)
6210 if (r_shadow_selectedlight == light)
6211 r_shadow_selectedlight = NULL;
6212 R_RTLight_Uncompile(&light->rtlight);
6213 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
6216 void R_Shadow_ClearWorldLights(void)
6220 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6221 for (lightindex = 0;lightindex < range;lightindex++)
6223 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6225 R_Shadow_FreeWorldLight(light);
6227 r_shadow_selectedlight = NULL;
6230 static void R_Shadow_SelectLight(dlight_t *light)
6232 if (r_shadow_selectedlight)
6233 r_shadow_selectedlight->selected = false;
6234 r_shadow_selectedlight = light;
6235 if (r_shadow_selectedlight)
6236 r_shadow_selectedlight->selected = true;
6239 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6241 // this is never batched (there can be only one)
6243 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
6244 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6245 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6248 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6253 skinframe_t *skinframe;
6256 // this is never batched (due to the ent parameter changing every time)
6257 // so numsurfaces == 1 and surfacelist[0] == lightnumber
6258 const dlight_t *light = (dlight_t *)ent;
6261 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
6264 VectorScale(light->color, intensity, spritecolor);
6265 if (VectorLength(spritecolor) < 0.1732f)
6266 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
6267 if (VectorLength(spritecolor) > 1.0f)
6268 VectorNormalize(spritecolor);
6270 // draw light sprite
6271 if (light->cubemapname[0] && !light->shadow)
6272 skinframe = r_editlights_sprcubemapnoshadowlight;
6273 else if (light->cubemapname[0])
6274 skinframe = r_editlights_sprcubemaplight;
6275 else if (!light->shadow)
6276 skinframe = r_editlights_sprnoshadowlight;
6278 skinframe = r_editlights_sprlight;
6280 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);
6281 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6283 // draw selection sprite if light is selected
6284 if (light->selected)
6286 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
6287 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
6288 // VorteX todo: add normalmode/realtime mode light overlay sprites?
6292 void R_Shadow_DrawLightSprites(void)
6296 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6297 for (lightindex = 0;lightindex < range;lightindex++)
6299 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6301 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
6303 if (!r_editlights_lockcursor)
6304 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
6307 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
6312 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6313 if (lightindex >= range)
6315 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6318 rtlight = &light->rtlight;
6319 //if (!(rtlight->flags & flag))
6321 VectorCopy(rtlight->shadoworigin, origin);
6322 *radius = rtlight->radius;
6323 VectorCopy(rtlight->color, color);
6327 static void R_Shadow_SelectLightInView(void)
6329 float bestrating, rating, temp[3];
6333 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6337 if (r_editlights_lockcursor)
6339 for (lightindex = 0;lightindex < range;lightindex++)
6341 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6344 VectorSubtract(light->origin, r_refdef.view.origin, temp);
6345 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
6348 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
6349 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1.0f)
6351 bestrating = rating;
6356 R_Shadow_SelectLight(best);
6359 void R_Shadow_LoadWorldLights(void)
6361 int n, a, style, shadow, flags;
6362 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
6363 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
6364 if (cl.worldmodel == NULL)
6366 Con_Print("No map loaded.\n");
6369 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6370 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6380 for (;COM_Parse(t, true) && strcmp(
6381 if (COM_Parse(t, true))
6383 if (com_token[0] == '!')
6386 origin[0] = atof(com_token+1);
6389 origin[0] = atof(com_token);
6394 while (*s && *s != '\n' && *s != '\r')
6400 // check for modifier flags
6407 #if _MSC_VER >= 1400
6408 #define sscanf sscanf_s
6410 cubemapname[sizeof(cubemapname)-1] = 0;
6411 #if MAX_QPATH != 128
6412 #error update this code if MAX_QPATH changes
6414 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
6415 #if _MSC_VER >= 1400
6416 , sizeof(cubemapname)
6418 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
6421 flags = LIGHTFLAG_REALTIMEMODE;
6429 coronasizescale = 0.25f;
6431 VectorClear(angles);
6434 if (a < 9 || !strcmp(cubemapname, "\"\""))
6436 // remove quotes on cubemapname
6437 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
6440 namelen = strlen(cubemapname) - 2;
6441 memmove(cubemapname, cubemapname + 1, namelen);
6442 cubemapname[namelen] = '\0';
6446 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);
6449 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6457 Con_Printf("invalid rtlights file \"%s\"\n", name);
6458 Mem_Free(lightsstring);
6462 void R_Shadow_SaveWorldLights(void)
6466 size_t bufchars, bufmaxchars;
6468 char name[MAX_QPATH];
6469 char line[MAX_INPUTLINE];
6470 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
6471 // I hate lines which are 3 times my screen size :( --blub
6474 if (cl.worldmodel == NULL)
6476 Con_Print("No map loaded.\n");
6479 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6480 bufchars = bufmaxchars = 0;
6482 for (lightindex = 0;lightindex < range;lightindex++)
6484 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6487 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
6488 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);
6489 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
6490 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]);
6492 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);
6493 if (bufchars + strlen(line) > bufmaxchars)
6495 bufmaxchars = bufchars + strlen(line) + 2048;
6497 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
6501 memcpy(buf, oldbuf, bufchars);
6507 memcpy(buf + bufchars, line, strlen(line));
6508 bufchars += strlen(line);
6512 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
6517 void R_Shadow_LoadLightsFile(void)
6520 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
6521 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
6522 if (cl.worldmodel == NULL)
6524 Con_Print("No map loaded.\n");
6527 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
6528 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6536 while (*s && *s != '\n' && *s != '\r')
6542 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);
6546 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);
6549 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
6550 radius = bound(15, radius, 4096);
6551 VectorScale(color, (2.0f / (8388608.0f)), color);
6552 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6560 Con_Printf("invalid lights file \"%s\"\n", name);
6561 Mem_Free(lightsstring);
6565 // tyrlite/hmap2 light types in the delay field
6566 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
6568 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
6580 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
6581 char key[256], value[MAX_INPUTLINE];
6584 if (cl.worldmodel == NULL)
6586 Con_Print("No map loaded.\n");
6589 // try to load a .ent file first
6590 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
6591 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
6592 // and if that is not found, fall back to the bsp file entity string
6594 data = cl.worldmodel->brush.entities;
6597 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
6599 type = LIGHTTYPE_MINUSX;
6600 origin[0] = origin[1] = origin[2] = 0;
6601 originhack[0] = originhack[1] = originhack[2] = 0;
6602 angles[0] = angles[1] = angles[2] = 0;
6603 color[0] = color[1] = color[2] = 1;
6604 light[0] = light[1] = light[2] = 1;light[3] = 300;
6605 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
6615 if (!COM_ParseToken_Simple(&data, false, false, true))
6617 if (com_token[0] == '}')
6618 break; // end of entity
6619 if (com_token[0] == '_')
6620 strlcpy(key, com_token + 1, sizeof(key));
6622 strlcpy(key, com_token, sizeof(key));
6623 while (key[strlen(key)-1] == ' ') // remove trailing spaces
6624 key[strlen(key)-1] = 0;
6625 if (!COM_ParseToken_Simple(&data, false, false, true))
6627 strlcpy(value, com_token, sizeof(value));
6629 // now that we have the key pair worked out...
6630 if (!strcmp("light", key))
6632 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
6636 light[0] = vec[0] * (1.0f / 256.0f);
6637 light[1] = vec[0] * (1.0f / 256.0f);
6638 light[2] = vec[0] * (1.0f / 256.0f);
6644 light[0] = vec[0] * (1.0f / 255.0f);
6645 light[1] = vec[1] * (1.0f / 255.0f);
6646 light[2] = vec[2] * (1.0f / 255.0f);
6650 else if (!strcmp("delay", key))
6652 else if (!strcmp("origin", key))
6653 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
6654 else if (!strcmp("angle", key))
6655 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
6656 else if (!strcmp("angles", key))
6657 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
6658 else if (!strcmp("color", key))
6659 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
6660 else if (!strcmp("wait", key))
6661 fadescale = atof(value);
6662 else if (!strcmp("classname", key))
6664 if (!strncmp(value, "light", 5))
6667 if (!strcmp(value, "light_fluoro"))
6672 overridecolor[0] = 1;
6673 overridecolor[1] = 1;
6674 overridecolor[2] = 1;
6676 if (!strcmp(value, "light_fluorospark"))
6681 overridecolor[0] = 1;
6682 overridecolor[1] = 1;
6683 overridecolor[2] = 1;
6685 if (!strcmp(value, "light_globe"))
6690 overridecolor[0] = 1;
6691 overridecolor[1] = 0.8;
6692 overridecolor[2] = 0.4;
6694 if (!strcmp(value, "light_flame_large_yellow"))
6699 overridecolor[0] = 1;
6700 overridecolor[1] = 0.5;
6701 overridecolor[2] = 0.1;
6703 if (!strcmp(value, "light_flame_small_yellow"))
6708 overridecolor[0] = 1;
6709 overridecolor[1] = 0.5;
6710 overridecolor[2] = 0.1;
6712 if (!strcmp(value, "light_torch_small_white"))
6717 overridecolor[0] = 1;
6718 overridecolor[1] = 0.5;
6719 overridecolor[2] = 0.1;
6721 if (!strcmp(value, "light_torch_small_walltorch"))
6726 overridecolor[0] = 1;
6727 overridecolor[1] = 0.5;
6728 overridecolor[2] = 0.1;
6732 else if (!strcmp("style", key))
6733 style = atoi(value);
6734 else if (!strcmp("skin", key))
6735 skin = (int)atof(value);
6736 else if (!strcmp("pflags", key))
6737 pflags = (int)atof(value);
6738 //else if (!strcmp("effects", key))
6739 // effects = (int)atof(value);
6740 else if (cl.worldmodel->type == mod_brushq3)
6742 if (!strcmp("scale", key))
6743 lightscale = atof(value);
6744 if (!strcmp("fade", key))
6745 fadescale = atof(value);
6750 if (lightscale <= 0)
6754 if (color[0] == color[1] && color[0] == color[2])
6756 color[0] *= overridecolor[0];
6757 color[1] *= overridecolor[1];
6758 color[2] *= overridecolor[2];
6760 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
6761 color[0] = color[0] * light[0];
6762 color[1] = color[1] * light[1];
6763 color[2] = color[2] * light[2];
6766 case LIGHTTYPE_MINUSX:
6768 case LIGHTTYPE_RECIPX:
6770 VectorScale(color, (1.0f / 16.0f), color);
6772 case LIGHTTYPE_RECIPXX:
6774 VectorScale(color, (1.0f / 16.0f), color);
6777 case LIGHTTYPE_NONE:
6781 case LIGHTTYPE_MINUSXX:
6784 VectorAdd(origin, originhack, origin);
6786 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);
6789 Mem_Free(entfiledata);
6793 static void R_Shadow_SetCursorLocationForView(void)
6796 vec3_t dest, endpos;
6798 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
6799 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
6800 if (trace.fraction < 1)
6802 dist = trace.fraction * r_editlights_cursordistance.value;
6803 push = r_editlights_cursorpushback.value;
6807 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
6808 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
6812 VectorClear( endpos );
6814 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6815 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6816 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6819 void R_Shadow_UpdateWorldLightSelection(void)
6821 if (r_editlights.integer)
6823 R_Shadow_SetCursorLocationForView();
6824 R_Shadow_SelectLightInView();
6827 R_Shadow_SelectLight(NULL);
6830 static void R_Shadow_EditLights_Clear_f(void)
6832 R_Shadow_ClearWorldLights();
6835 void R_Shadow_EditLights_Reload_f(void)
6839 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
6840 R_Shadow_ClearWorldLights();
6841 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
6843 R_Shadow_LoadWorldLights();
6844 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6845 R_Shadow_LoadLightsFile();
6847 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
6849 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6850 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6854 static void R_Shadow_EditLights_Save_f(void)
6858 R_Shadow_SaveWorldLights();
6861 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6863 R_Shadow_ClearWorldLights();
6864 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6867 static void R_Shadow_EditLights_ImportLightsFile_f(void)
6869 R_Shadow_ClearWorldLights();
6870 R_Shadow_LoadLightsFile();
6873 static void R_Shadow_EditLights_Spawn_f(void)
6876 if (!r_editlights.integer)
6878 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6881 if (Cmd_Argc() != 1)
6883 Con_Print("r_editlights_spawn does not take parameters\n");
6886 color[0] = color[1] = color[2] = 1;
6887 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6890 static void R_Shadow_EditLights_Edit_f(void)
6892 vec3_t origin, angles, color;
6893 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6894 int style, shadows, flags, normalmode, realtimemode;
6895 char cubemapname[MAX_INPUTLINE];
6896 if (!r_editlights.integer)
6898 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6901 if (!r_shadow_selectedlight)
6903 Con_Print("No selected light.\n");
6906 VectorCopy(r_shadow_selectedlight->origin, origin);
6907 VectorCopy(r_shadow_selectedlight->angles, angles);
6908 VectorCopy(r_shadow_selectedlight->color, color);
6909 radius = r_shadow_selectedlight->radius;
6910 style = r_shadow_selectedlight->style;
6911 if (r_shadow_selectedlight->cubemapname)
6912 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6915 shadows = r_shadow_selectedlight->shadow;
6916 corona = r_shadow_selectedlight->corona;
6917 coronasizescale = r_shadow_selectedlight->coronasizescale;
6918 ambientscale = r_shadow_selectedlight->ambientscale;
6919 diffusescale = r_shadow_selectedlight->diffusescale;
6920 specularscale = r_shadow_selectedlight->specularscale;
6921 flags = r_shadow_selectedlight->flags;
6922 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6923 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6924 if (!strcmp(Cmd_Argv(1), "origin"))
6926 if (Cmd_Argc() != 5)
6928 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6931 origin[0] = atof(Cmd_Argv(2));
6932 origin[1] = atof(Cmd_Argv(3));
6933 origin[2] = atof(Cmd_Argv(4));
6935 else if (!strcmp(Cmd_Argv(1), "originscale"))
6937 if (Cmd_Argc() != 5)
6939 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6942 origin[0] *= atof(Cmd_Argv(2));
6943 origin[1] *= atof(Cmd_Argv(3));
6944 origin[2] *= atof(Cmd_Argv(4));
6946 else if (!strcmp(Cmd_Argv(1), "originx"))
6948 if (Cmd_Argc() != 3)
6950 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6953 origin[0] = atof(Cmd_Argv(2));
6955 else if (!strcmp(Cmd_Argv(1), "originy"))
6957 if (Cmd_Argc() != 3)
6959 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6962 origin[1] = atof(Cmd_Argv(2));
6964 else if (!strcmp(Cmd_Argv(1), "originz"))
6966 if (Cmd_Argc() != 3)
6968 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6971 origin[2] = atof(Cmd_Argv(2));
6973 else if (!strcmp(Cmd_Argv(1), "move"))
6975 if (Cmd_Argc() != 5)
6977 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6980 origin[0] += atof(Cmd_Argv(2));
6981 origin[1] += atof(Cmd_Argv(3));
6982 origin[2] += atof(Cmd_Argv(4));
6984 else if (!strcmp(Cmd_Argv(1), "movex"))
6986 if (Cmd_Argc() != 3)
6988 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6991 origin[0] += atof(Cmd_Argv(2));
6993 else if (!strcmp(Cmd_Argv(1), "movey"))
6995 if (Cmd_Argc() != 3)
6997 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7000 origin[1] += atof(Cmd_Argv(2));
7002 else if (!strcmp(Cmd_Argv(1), "movez"))
7004 if (Cmd_Argc() != 3)
7006 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7009 origin[2] += atof(Cmd_Argv(2));
7011 else if (!strcmp(Cmd_Argv(1), "angles"))
7013 if (Cmd_Argc() != 5)
7015 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
7018 angles[0] = atof(Cmd_Argv(2));
7019 angles[1] = atof(Cmd_Argv(3));
7020 angles[2] = atof(Cmd_Argv(4));
7022 else if (!strcmp(Cmd_Argv(1), "anglesx"))
7024 if (Cmd_Argc() != 3)
7026 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7029 angles[0] = atof(Cmd_Argv(2));
7031 else if (!strcmp(Cmd_Argv(1), "anglesy"))
7033 if (Cmd_Argc() != 3)
7035 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7038 angles[1] = atof(Cmd_Argv(2));
7040 else if (!strcmp(Cmd_Argv(1), "anglesz"))
7042 if (Cmd_Argc() != 3)
7044 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7047 angles[2] = atof(Cmd_Argv(2));
7049 else if (!strcmp(Cmd_Argv(1), "color"))
7051 if (Cmd_Argc() != 5)
7053 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
7056 color[0] = atof(Cmd_Argv(2));
7057 color[1] = atof(Cmd_Argv(3));
7058 color[2] = atof(Cmd_Argv(4));
7060 else if (!strcmp(Cmd_Argv(1), "radius"))
7062 if (Cmd_Argc() != 3)
7064 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7067 radius = atof(Cmd_Argv(2));
7069 else if (!strcmp(Cmd_Argv(1), "colorscale"))
7071 if (Cmd_Argc() == 3)
7073 double scale = atof(Cmd_Argv(2));
7080 if (Cmd_Argc() != 5)
7082 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
7085 color[0] *= atof(Cmd_Argv(2));
7086 color[1] *= atof(Cmd_Argv(3));
7087 color[2] *= atof(Cmd_Argv(4));
7090 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
7092 if (Cmd_Argc() != 3)
7094 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7097 radius *= atof(Cmd_Argv(2));
7099 else if (!strcmp(Cmd_Argv(1), "style"))
7101 if (Cmd_Argc() != 3)
7103 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7106 style = atoi(Cmd_Argv(2));
7108 else if (!strcmp(Cmd_Argv(1), "cubemap"))
7112 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7115 if (Cmd_Argc() == 3)
7116 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
7120 else if (!strcmp(Cmd_Argv(1), "shadows"))
7122 if (Cmd_Argc() != 3)
7124 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7127 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7129 else if (!strcmp(Cmd_Argv(1), "corona"))
7131 if (Cmd_Argc() != 3)
7133 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7136 corona = atof(Cmd_Argv(2));
7138 else if (!strcmp(Cmd_Argv(1), "coronasize"))
7140 if (Cmd_Argc() != 3)
7142 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7145 coronasizescale = atof(Cmd_Argv(2));
7147 else if (!strcmp(Cmd_Argv(1), "ambient"))
7149 if (Cmd_Argc() != 3)
7151 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7154 ambientscale = atof(Cmd_Argv(2));
7156 else if (!strcmp(Cmd_Argv(1), "diffuse"))
7158 if (Cmd_Argc() != 3)
7160 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7163 diffusescale = atof(Cmd_Argv(2));
7165 else if (!strcmp(Cmd_Argv(1), "specular"))
7167 if (Cmd_Argc() != 3)
7169 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7172 specularscale = atof(Cmd_Argv(2));
7174 else if (!strcmp(Cmd_Argv(1), "normalmode"))
7176 if (Cmd_Argc() != 3)
7178 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7181 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7183 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
7185 if (Cmd_Argc() != 3)
7187 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
7190 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
7194 Con_Print("usage: r_editlights_edit [property] [value]\n");
7195 Con_Print("Selected light's properties:\n");
7196 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7197 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7198 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7199 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
7200 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
7201 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
7202 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
7203 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
7204 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
7205 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
7206 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
7207 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
7208 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
7209 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
7212 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
7213 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
7216 static void R_Shadow_EditLights_EditAll_f(void)
7219 dlight_t *light, *oldselected;
7222 if (!r_editlights.integer)
7224 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
7228 oldselected = r_shadow_selectedlight;
7229 // EditLights doesn't seem to have a "remove" command or something so:
7230 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7231 for (lightindex = 0;lightindex < range;lightindex++)
7233 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7236 R_Shadow_SelectLight(light);
7237 R_Shadow_EditLights_Edit_f();
7239 // return to old selected (to not mess editing once selection is locked)
7240 R_Shadow_SelectLight(oldselected);
7243 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
7245 int lightnumber, lightcount;
7246 size_t lightindex, range;
7251 if (!r_editlights.integer)
7254 // update cvars so QC can query them
7255 if (r_shadow_selectedlight)
7257 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
7258 Cvar_SetQuick(&r_editlights_current_origin, temp);
7259 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
7260 Cvar_SetQuick(&r_editlights_current_angles, temp);
7261 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
7262 Cvar_SetQuick(&r_editlights_current_color, temp);
7263 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
7264 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
7265 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
7266 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
7267 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
7268 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
7269 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
7270 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
7271 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
7272 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
7273 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
7276 // draw properties on screen
7277 if (!r_editlights_drawproperties.integer)
7279 x = vid_conwidth.value - 320;
7281 DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
7284 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
7285 for (lightindex = 0;lightindex < range;lightindex++)
7287 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
7290 if (light == r_shadow_selectedlight)
7291 lightnumber = (int)lightindex;
7294 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;
7295 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;
7297 if (r_shadow_selectedlight == NULL)
7299 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;
7300 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;
7301 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;
7302 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;
7303 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;
7304 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;
7305 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;
7306 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;
7307 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;
7308 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;
7309 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;
7310 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;
7311 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;
7312 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;
7313 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;
7315 dpsnprintf(temp, sizeof(temp), "Render stats\n"); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7316 dpsnprintf(temp, sizeof(temp), "Current color: %.3f %.3f %.3f\n", r_shadow_selectedlight->rtlight.currentcolor[0], r_shadow_selectedlight->rtlight.currentcolor[1], r_shadow_selectedlight->rtlight.currentcolor[2]); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7317 dpsnprintf(temp, sizeof(temp), "Shadow size : %ix%ix6\n", r_shadow_selectedlight->rtlight.shadowmapatlassidesize, r_shadow_selectedlight->rtlight.shadowmapatlassidesize); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7318 dpsnprintf(temp, sizeof(temp), "World surfs : %i\n", r_shadow_selectedlight->rtlight.cached_numsurfaces); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7319 dpsnprintf(temp, sizeof(temp), "Shadow ents : %i + %i noself\n", r_shadow_selectedlight->rtlight.cached_numshadowentities, r_shadow_selectedlight->rtlight.cached_numshadowentities_noselfshadow); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7320 dpsnprintf(temp, sizeof(temp), "Lit ents : %i + %i noself\n", r_shadow_selectedlight->rtlight.cached_numlightentities, r_shadow_selectedlight->rtlight.cached_numlightentities_noselfshadow); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7321 dpsnprintf(temp, sizeof(temp), "BG photons : %.3f\n", r_shadow_selectedlight->rtlight.bouncegrid_photons); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7322 dpsnprintf(temp, sizeof(temp), "BG radius : %.0f\n", r_shadow_selectedlight->rtlight.bouncegrid_effectiveradius); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7323 dpsnprintf(temp, sizeof(temp), "BG color : %.3f %.3f %.3f\n", r_shadow_selectedlight->rtlight.bouncegrid_photoncolor[0], r_shadow_selectedlight->rtlight.bouncegrid_photoncolor[1], r_shadow_selectedlight->rtlight.bouncegrid_photoncolor[2]); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7324 dpsnprintf(temp, sizeof(temp), "BG stats : %i traces %i hits\n", r_shadow_selectedlight->rtlight.bouncegrid_traces, r_shadow_selectedlight->rtlight.bouncegrid_hits); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); y += 8;
7327 static void R_Shadow_EditLights_ToggleShadow_f(void)
7329 if (!r_editlights.integer)
7331 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7334 if (!r_shadow_selectedlight)
7336 Con_Print("No selected light.\n");
7339 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);
7342 static void R_Shadow_EditLights_ToggleCorona_f(void)
7344 if (!r_editlights.integer)
7346 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
7349 if (!r_shadow_selectedlight)
7351 Con_Print("No selected light.\n");
7354 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);
7357 static void R_Shadow_EditLights_Remove_f(void)
7359 if (!r_editlights.integer)
7361 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
7364 if (!r_shadow_selectedlight)
7366 Con_Print("No selected light.\n");
7369 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
7370 r_shadow_selectedlight = NULL;
7373 static void R_Shadow_EditLights_Help_f(void)
7376 "Documentation on r_editlights system:\n"
7378 "r_editlights : enable/disable editing mode\n"
7379 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
7380 "r_editlights_cursorpushback : push back cursor this far from surface\n"
7381 "r_editlights_cursorpushoff : push cursor off surface this far\n"
7382 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
7383 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
7385 "r_editlights_help : this help\n"
7386 "r_editlights_clear : remove all lights\n"
7387 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
7388 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
7389 "r_editlights_save : save to .rtlights file\n"
7390 "r_editlights_spawn : create a light with default settings\n"
7391 "r_editlights_edit command : edit selected light - more documentation below\n"
7392 "r_editlights_remove : remove selected light\n"
7393 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
7394 "r_editlights_importlightentitiesfrommap : reload light entities\n"
7395 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
7397 "origin x y z : set light location\n"
7398 "originx x: set x component of light location\n"
7399 "originy y: set y component of light location\n"
7400 "originz z: set z component of light location\n"
7401 "move x y z : adjust light location\n"
7402 "movex x: adjust x component of light location\n"
7403 "movey y: adjust y component of light location\n"
7404 "movez z: adjust z component of light location\n"
7405 "angles x y z : set light angles\n"
7406 "anglesx x: set x component of light angles\n"
7407 "anglesy y: set y component of light angles\n"
7408 "anglesz z: set z component of light angles\n"
7409 "color r g b : set color of light (can be brighter than 1 1 1)\n"
7410 "radius radius : set radius (size) of light\n"
7411 "colorscale grey : multiply color of light (1 does nothing)\n"
7412 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
7413 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
7414 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
7415 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
7416 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
7417 "cubemap basename : set filter cubemap of light\n"
7418 "shadows 1/0 : turn on/off shadows\n"
7419 "corona n : set corona intensity\n"
7420 "coronasize n : set corona size (0-1)\n"
7421 "ambient n : set ambient intensity (0-1)\n"
7422 "diffuse n : set diffuse intensity (0-1)\n"
7423 "specular n : set specular intensity (0-1)\n"
7424 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
7425 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
7426 "<nothing> : print light properties to console\n"
7430 static void R_Shadow_EditLights_CopyInfo_f(void)
7432 if (!r_editlights.integer)
7434 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
7437 if (!r_shadow_selectedlight)
7439 Con_Print("No selected light.\n");
7442 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
7443 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
7444 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
7445 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
7446 if (r_shadow_selectedlight->cubemapname)
7447 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
7449 r_shadow_bufferlight.cubemapname[0] = 0;
7450 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
7451 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
7452 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
7453 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
7454 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
7455 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
7456 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
7459 static void R_Shadow_EditLights_PasteInfo_f(void)
7461 if (!r_editlights.integer)
7463 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
7466 if (!r_shadow_selectedlight)
7468 Con_Print("No selected light.\n");
7471 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);
7474 static void R_Shadow_EditLights_Lock_f(void)
7476 if (!r_editlights.integer)
7478 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
7481 if (r_editlights_lockcursor)
7483 r_editlights_lockcursor = false;
7486 if (!r_shadow_selectedlight)
7488 Con_Print("No selected light to lock on.\n");
7491 r_editlights_lockcursor = true;
7494 static void R_Shadow_EditLights_Init(void)
7496 Cvar_RegisterVariable(&r_editlights);
7497 Cvar_RegisterVariable(&r_editlights_cursordistance);
7498 Cvar_RegisterVariable(&r_editlights_cursorpushback);
7499 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
7500 Cvar_RegisterVariable(&r_editlights_cursorgrid);
7501 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
7502 Cvar_RegisterVariable(&r_editlights_drawproperties);
7503 Cvar_RegisterVariable(&r_editlights_current_origin);
7504 Cvar_RegisterVariable(&r_editlights_current_angles);
7505 Cvar_RegisterVariable(&r_editlights_current_color);
7506 Cvar_RegisterVariable(&r_editlights_current_radius);
7507 Cvar_RegisterVariable(&r_editlights_current_corona);
7508 Cvar_RegisterVariable(&r_editlights_current_coronasize);
7509 Cvar_RegisterVariable(&r_editlights_current_style);
7510 Cvar_RegisterVariable(&r_editlights_current_shadows);
7511 Cvar_RegisterVariable(&r_editlights_current_cubemap);
7512 Cvar_RegisterVariable(&r_editlights_current_ambient);
7513 Cvar_RegisterVariable(&r_editlights_current_diffuse);
7514 Cvar_RegisterVariable(&r_editlights_current_specular);
7515 Cvar_RegisterVariable(&r_editlights_current_normalmode);
7516 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
7517 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
7518 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
7519 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)");
7520 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
7521 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
7522 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
7523 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)");
7524 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
7525 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
7526 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
7527 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
7528 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
7529 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
7530 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)");
7531 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
7537 =============================================================================
7541 =============================================================================
7544 void R_CompleteLightPoint(float *ambient, float *diffuse, float *lightdir, const vec3_t p, const int flags, float lightmapintensity, float ambientintensity)
7546 int i, numlights, flag, q;
7549 float relativepoint[3];
7554 float sa[3], sx[3], sy[3], sz[3], sd[3];
7557 // use first order spherical harmonics to combine directional lights
7558 for (q = 0; q < 3; q++)
7559 sa[q] = sx[q] = sy[q] = sz[q] = sd[q] = 0;
7561 if (flags & LP_LIGHTMAP)
7563 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7565 float tempambient[3];
7566 for (q = 0; q < 3; q++)
7567 tempambient[q] = color[q] = relativepoint[q] = 0;
7568 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
7569 // calculate a weighted average light direction as well
7570 intensity = VectorLength(color);
7571 for (q = 0; q < 3; q++)
7573 sa[q] += (0.5f * color[q] + tempambient[q]) * lightmapintensity;
7574 sx[q] += (relativepoint[0] * color[q]) * lightmapintensity;
7575 sy[q] += (relativepoint[1] * color[q]) * lightmapintensity;
7576 sz[q] += (relativepoint[2] * color[q]) * lightmapintensity;
7577 sd[q] += (intensity * relativepoint[q]) * lightmapintensity;
7582 // unlit map - fullbright but scaled by lightmapintensity
7583 for (q = 0; q < 3; q++)
7584 sa[q] += lightmapintensity;
7588 if (flags & LP_RTWORLD)
7590 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7591 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7592 for (i = 0; i < numlights; i++)
7594 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7597 light = &dlight->rtlight;
7598 if (!(light->flags & flag))
7601 lightradius2 = light->radius * light->radius;
7602 VectorSubtract(light->shadoworigin, p, relativepoint);
7603 dist2 = VectorLength2(relativepoint);
7604 if (dist2 >= lightradius2)
7606 dist = sqrt(dist2) / light->radius;
7607 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
7608 if (intensity <= 0.0f)
7610 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
7612 for (q = 0; q < 3; q++)
7613 color[q] = light->currentcolor[q] * intensity;
7614 intensity = VectorLength(color);
7615 VectorNormalize(relativepoint);
7616 for (q = 0; q < 3; q++)
7618 sa[q] += 0.5f * color[q];
7619 sx[q] += relativepoint[0] * color[q];
7620 sy[q] += relativepoint[1] * color[q];
7621 sz[q] += relativepoint[2] * color[q];
7622 sd[q] += intensity * relativepoint[q];
7625 // FIXME: sample bouncegrid too!
7628 if (flags & LP_DYNLIGHT)
7631 for (i = 0;i < r_refdef.scene.numlights;i++)
7633 light = r_refdef.scene.lights[i];
7635 lightradius2 = light->radius * light->radius;
7636 VectorSubtract(light->shadoworigin, p, relativepoint);
7637 dist2 = VectorLength2(relativepoint);
7638 if (dist2 >= lightradius2)
7640 dist = sqrt(dist2) / light->radius;
7641 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
7642 if (intensity <= 0.0f)
7644 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
7646 for (q = 0; q < 3; q++)
7647 color[q] = light->currentcolor[q] * intensity;
7648 intensity = VectorLength(color);
7649 VectorNormalize(relativepoint);
7650 for (q = 0; q < 3; q++)
7652 sa[q] += 0.5f * color[q];
7653 sx[q] += relativepoint[0] * color[q];
7654 sy[q] += relativepoint[1] * color[q];
7655 sz[q] += relativepoint[2] * color[q];
7656 sd[q] += intensity * relativepoint[q];
7661 // calculate the weighted-average light direction (bentnormal)
7662 for (q = 0; q < 3; q++)
7663 lightdir[q] = sd[q];
7664 VectorNormalize(lightdir);
7665 for (q = 0; q < 3; q++)
7667 // extract the diffuse color along the chosen direction and scale it
7668 diffuse[q] = (lightdir[0] * sx[q] + lightdir[1] * sy[q] + lightdir[2] * sz[q]);
7669 // subtract some of diffuse from ambient
7670 ambient[q] = sa[q] + -0.333f * diffuse[q] + ambientintensity;