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 qboolean r_shadow_usingshadowmap2d;
183 qboolean r_shadow_usingshadowmaportho;
184 int r_shadow_shadowmapside;
185 float r_shadow_shadowmap_texturescale[2];
186 float r_shadow_shadowmap_parameters[4];
188 int r_shadow_drawbuffer;
189 int r_shadow_readbuffer;
191 int r_shadow_cullface_front, r_shadow_cullface_back;
192 GLuint r_shadow_fbo2d;
193 r_shadow_shadowmode_t r_shadow_shadowmode;
194 int r_shadow_shadowmapfilterquality;
195 int r_shadow_shadowmapdepthbits;
196 int r_shadow_shadowmapmaxsize;
197 qboolean r_shadow_shadowmapvsdct;
198 qboolean r_shadow_shadowmapsampler;
199 qboolean r_shadow_shadowmapshadowsampler;
200 int r_shadow_shadowmappcf;
201 int r_shadow_shadowmapborder;
202 matrix4x4_t r_shadow_shadowmapmatrix;
203 int r_shadow_lightscissor[4];
204 qboolean r_shadow_usingdeferredprepass;
206 int maxshadowtriangles;
209 int maxshadowvertices;
210 float *shadowvertex3f;
220 unsigned char *shadowsides;
221 int *shadowsideslist;
228 int r_shadow_buffer_numleafpvsbytes;
229 unsigned char *r_shadow_buffer_visitingleafpvs;
230 unsigned char *r_shadow_buffer_leafpvs;
231 int *r_shadow_buffer_leaflist;
233 int r_shadow_buffer_numsurfacepvsbytes;
234 unsigned char *r_shadow_buffer_surfacepvs;
235 int *r_shadow_buffer_surfacelist;
236 unsigned char *r_shadow_buffer_surfacesides;
238 int r_shadow_buffer_numshadowtrispvsbytes;
239 unsigned char *r_shadow_buffer_shadowtrispvs;
240 int r_shadow_buffer_numlighttrispvsbytes;
241 unsigned char *r_shadow_buffer_lighttrispvs;
243 rtexturepool_t *r_shadow_texturepool;
244 rtexture_t *r_shadow_attenuationgradienttexture;
245 rtexture_t *r_shadow_attenuation2dtexture;
246 rtexture_t *r_shadow_attenuation3dtexture;
247 skinframe_t *r_shadow_lightcorona;
248 rtexture_t *r_shadow_shadowmap2ddepthbuffer;
249 rtexture_t *r_shadow_shadowmap2ddepthtexture;
250 rtexture_t *r_shadow_shadowmapvsdcttexture;
251 int r_shadow_shadowmapsize; // changes for each light based on distance
252 int r_shadow_shadowmaplod; // changes for each light based on distance
254 GLuint r_shadow_prepassgeometryfbo;
255 GLuint r_shadow_prepasslightingdiffusespecularfbo;
256 GLuint r_shadow_prepasslightingdiffusefbo;
257 int r_shadow_prepass_width;
258 int r_shadow_prepass_height;
259 rtexture_t *r_shadow_prepassgeometrydepthbuffer;
260 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
261 rtexture_t *r_shadow_prepasslightingdiffusetexture;
262 rtexture_t *r_shadow_prepasslightingspeculartexture;
264 // keep track of the provided framebuffer info
265 static int r_shadow_fb_fbo;
266 static rtexture_t *r_shadow_fb_depthtexture;
267 static rtexture_t *r_shadow_fb_colortexture;
269 // lights are reloaded when this changes
270 char r_shadow_mapname[MAX_QPATH];
272 // used only for light filters (cubemaps)
273 rtexturepool_t *r_shadow_filters_texturepool;
275 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"};
276 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"};
277 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
278 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"};
279 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)"};
280 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
281 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)"};
282 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"};
283 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
284 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
285 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
286 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
287 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
288 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
289 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
290 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
291 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
292 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)"};
293 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
294 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
295 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
296 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
297 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)"};
298 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"};
299 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
300 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
301 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"};
302 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)"};
303 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
304 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)"};
305 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "1", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"};
306 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)"};
307 cvar_t r_shadow_shadowmapping_useshadowsampler = {CVAR_SAVE, "r_shadow_shadowmapping_useshadowsampler", "1", "whether to use sampler2DShadow if available"};
308 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
309 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
310 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
311 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
312 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"};
313 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
314 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
315 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
316 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
317 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
318 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
319 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
320 cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
321 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
322 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)"};
323 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)"};
324 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)"};
325 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"};
326 cvar_t r_shadow_bouncegrid_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_directionalshading", "0", "use diffuse shading rather than ambient, 3D texture becomes 8x as many pixels to hold the additional data"};
327 cvar_t r_shadow_bouncegrid_dlightparticlemultiplier = {CVAR_SAVE, "r_shadow_bouncegrid_dlightparticlemultiplier", "0", "if set to a high value like 16 this can make dlights look great, but 0 is recommended for performance reasons"};
328 cvar_t r_shadow_bouncegrid_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
329 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)"};
330 cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
331 cvar_t r_shadow_bouncegrid_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_lightradiusscale", "4", "particles stop at this fraction of light radius (can be more than 1)"};
332 cvar_t r_shadow_bouncegrid_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_maxbounce", "2", "maximum number of bounces for a particle (minimum is 0)"};
333 cvar_t r_shadow_bouncegrid_particlebounceintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particlebounceintensity", "1", "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"};
334 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "1", "brightness of particles contributing to bouncegrid texture"};
335 cvar_t r_shadow_bouncegrid_photons = {CVAR_SAVE, "r_shadow_bouncegrid_photons", "2000", "total photons to shoot per update, divided proportionately between lights"};
336 cvar_t r_shadow_bouncegrid_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_spacing", "64", "unit size of bouncegrid pixel"};
337 cvar_t r_shadow_bouncegrid_stablerandom = {CVAR_SAVE, "r_shadow_bouncegrid_stablerandom", "1", "make particle distribution consistent from frame to frame"};
338 cvar_t r_shadow_bouncegrid_static = {CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
339 cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
340 cvar_t r_shadow_bouncegrid_static_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_static_lightradiusscale", "10", "particles stop at this fraction of light radius (can be more than 1) when in static mode"};
341 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"};
342 cvar_t r_shadow_bouncegrid_static_photons = {CVAR_SAVE, "r_shadow_bouncegrid_static_photons", "25000", "photons value to use when in static mode"};
343 cvar_t r_shadow_bouncegrid_updateinterval = {CVAR_SAVE, "r_shadow_bouncegrid_updateinterval", "0", "update bouncegrid texture once per this many seconds, useful values are 0, 0.05, or 1000000"};
344 cvar_t r_shadow_bouncegrid_x = {CVAR_SAVE, "r_shadow_bouncegrid_x", "64", "maximum texture size of bouncegrid on X axis"};
345 cvar_t r_shadow_bouncegrid_y = {CVAR_SAVE, "r_shadow_bouncegrid_y", "64", "maximum texture size of bouncegrid on Y axis"};
346 cvar_t r_shadow_bouncegrid_z = {CVAR_SAVE, "r_shadow_bouncegrid_z", "32", "maximum texture size of bouncegrid on Z axis"};
347 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
348 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"};
349 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
350 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
351 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
352 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
353 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
354 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
355 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
356 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
357 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
358 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
360 typedef struct r_shadow_bouncegrid_settings_s
363 qboolean bounceanglediffuse;
364 qboolean directionalshading;
365 qboolean includedirectlighting;
366 float dlightparticlemultiplier;
368 float lightradiusscale;
370 float particlebounceintensity;
371 float particleintensity;
376 r_shadow_bouncegrid_settings_t;
378 r_shadow_bouncegrid_settings_t r_shadow_bouncegridsettings;
379 rtexture_t *r_shadow_bouncegridtexture;
380 matrix4x4_t r_shadow_bouncegridmatrix;
381 vec_t r_shadow_bouncegridintensity;
382 qboolean r_shadow_bouncegriddirectional;
383 static double r_shadow_bouncegridtime;
384 static int r_shadow_bouncegridresolution[3];
385 static int r_shadow_bouncegridnumpixels;
386 static unsigned char *r_shadow_bouncegridpixels;
387 static float *r_shadow_bouncegridhighpixels;
389 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
390 #define ATTENTABLESIZE 256
391 // 1D gradient, 2D circle and 3D sphere attenuation textures
392 #define ATTEN1DSIZE 32
393 #define ATTEN2DSIZE 64
394 #define ATTEN3DSIZE 32
396 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
397 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
398 static float r_shadow_attentable[ATTENTABLESIZE+1];
400 rtlight_t *r_shadow_compilingrtlight;
401 static memexpandablearray_t r_shadow_worldlightsarray;
402 dlight_t *r_shadow_selectedlight;
403 dlight_t r_shadow_bufferlight;
404 vec3_t r_editlights_cursorlocation;
405 qboolean r_editlights_lockcursor;
407 extern int con_vislines;
409 void R_Shadow_UncompileWorldLights(void);
410 void R_Shadow_ClearWorldLights(void);
411 void R_Shadow_SaveWorldLights(void);
412 void R_Shadow_LoadWorldLights(void);
413 void R_Shadow_LoadLightsFile(void);
414 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
415 void R_Shadow_EditLights_Reload_f(void);
416 void R_Shadow_ValidateCvars(void);
417 static void R_Shadow_MakeTextures(void);
419 #define EDLIGHTSPRSIZE 8
420 skinframe_t *r_editlights_sprcursor;
421 skinframe_t *r_editlights_sprlight;
422 skinframe_t *r_editlights_sprnoshadowlight;
423 skinframe_t *r_editlights_sprcubemaplight;
424 skinframe_t *r_editlights_sprcubemapnoshadowlight;
425 skinframe_t *r_editlights_sprselection;
427 static void R_Shadow_SetShadowMode(void)
429 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
430 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
431 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
432 r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
433 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
434 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
435 r_shadow_shadowmaplod = -1;
436 r_shadow_shadowmapsize = 0;
437 r_shadow_shadowmapsampler = false;
438 r_shadow_shadowmappcf = 0;
439 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
440 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
442 switch(vid.renderpath)
444 case RENDERPATH_GL20:
445 if(r_shadow_shadowmapfilterquality < 0)
447 if (!r_fb.usedepthtextures)
448 r_shadow_shadowmappcf = 1;
449 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
450 r_shadow_shadowmappcf = 1;
451 else if(strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD"))
453 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
454 r_shadow_shadowmappcf = 1;
456 else if(strstr(gl_vendor, "ATI"))
457 r_shadow_shadowmappcf = 1;
459 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
463 switch (r_shadow_shadowmapfilterquality)
466 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
469 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
470 r_shadow_shadowmappcf = 1;
473 r_shadow_shadowmappcf = 1;
476 r_shadow_shadowmappcf = 2;
480 if (!r_fb.usedepthtextures)
481 r_shadow_shadowmapsampler = false;
482 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
484 case RENDERPATH_D3D9:
485 case RENDERPATH_D3D10:
486 case RENDERPATH_D3D11:
487 case RENDERPATH_SOFT:
488 r_shadow_shadowmapsampler = false;
489 r_shadow_shadowmappcf = 1;
490 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
492 case RENDERPATH_GL11:
493 case RENDERPATH_GL13:
494 case RENDERPATH_GLES1:
495 case RENDERPATH_GLES2:
501 qboolean R_Shadow_ShadowMappingEnabled(void)
503 switch (r_shadow_shadowmode)
505 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
512 static void R_Shadow_FreeShadowMaps(void)
514 R_Shadow_SetShadowMode();
516 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
520 if (r_shadow_shadowmap2ddepthtexture)
521 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
522 r_shadow_shadowmap2ddepthtexture = NULL;
524 if (r_shadow_shadowmap2ddepthbuffer)
525 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
526 r_shadow_shadowmap2ddepthbuffer = NULL;
528 if (r_shadow_shadowmapvsdcttexture)
529 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
530 r_shadow_shadowmapvsdcttexture = NULL;
533 static void r_shadow_start(void)
535 // allocate vertex processing arrays
536 r_shadow_bouncegridpixels = NULL;
537 r_shadow_bouncegridhighpixels = NULL;
538 r_shadow_bouncegridnumpixels = 0;
539 r_shadow_bouncegridtexture = NULL;
540 r_shadow_bouncegriddirectional = false;
541 r_shadow_attenuationgradienttexture = NULL;
542 r_shadow_attenuation2dtexture = NULL;
543 r_shadow_attenuation3dtexture = NULL;
544 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
545 r_shadow_shadowmap2ddepthtexture = NULL;
546 r_shadow_shadowmap2ddepthbuffer = NULL;
547 r_shadow_shadowmapvsdcttexture = NULL;
548 r_shadow_shadowmapmaxsize = 0;
549 r_shadow_shadowmapsize = 0;
550 r_shadow_shadowmaplod = 0;
551 r_shadow_shadowmapfilterquality = -1;
552 r_shadow_shadowmapdepthbits = 0;
553 r_shadow_shadowmapvsdct = false;
554 r_shadow_shadowmapsampler = false;
555 r_shadow_shadowmappcf = 0;
558 R_Shadow_FreeShadowMaps();
560 r_shadow_texturepool = NULL;
561 r_shadow_filters_texturepool = NULL;
562 R_Shadow_ValidateCvars();
563 R_Shadow_MakeTextures();
564 maxshadowtriangles = 0;
565 shadowelements = NULL;
566 maxshadowvertices = 0;
567 shadowvertex3f = NULL;
575 shadowmarklist = NULL;
580 shadowsideslist = NULL;
581 r_shadow_buffer_numleafpvsbytes = 0;
582 r_shadow_buffer_visitingleafpvs = NULL;
583 r_shadow_buffer_leafpvs = NULL;
584 r_shadow_buffer_leaflist = NULL;
585 r_shadow_buffer_numsurfacepvsbytes = 0;
586 r_shadow_buffer_surfacepvs = NULL;
587 r_shadow_buffer_surfacelist = NULL;
588 r_shadow_buffer_surfacesides = NULL;
589 r_shadow_buffer_numshadowtrispvsbytes = 0;
590 r_shadow_buffer_shadowtrispvs = NULL;
591 r_shadow_buffer_numlighttrispvsbytes = 0;
592 r_shadow_buffer_lighttrispvs = NULL;
594 r_shadow_usingdeferredprepass = false;
595 r_shadow_prepass_width = r_shadow_prepass_height = 0;
598 static void R_Shadow_FreeDeferred(void);
599 static void r_shadow_shutdown(void)
602 R_Shadow_UncompileWorldLights();
604 R_Shadow_FreeShadowMaps();
606 r_shadow_usingdeferredprepass = false;
607 if (r_shadow_prepass_width)
608 R_Shadow_FreeDeferred();
609 r_shadow_prepass_width = r_shadow_prepass_height = 0;
612 r_shadow_bouncegridtexture = NULL;
613 r_shadow_bouncegridpixels = NULL;
614 r_shadow_bouncegridhighpixels = NULL;
615 r_shadow_bouncegridnumpixels = 0;
616 r_shadow_bouncegriddirectional = false;
617 r_shadow_attenuationgradienttexture = NULL;
618 r_shadow_attenuation2dtexture = NULL;
619 r_shadow_attenuation3dtexture = NULL;
620 R_FreeTexturePool(&r_shadow_texturepool);
621 R_FreeTexturePool(&r_shadow_filters_texturepool);
622 maxshadowtriangles = 0;
624 Mem_Free(shadowelements);
625 shadowelements = NULL;
627 Mem_Free(shadowvertex3f);
628 shadowvertex3f = NULL;
631 Mem_Free(vertexupdate);
634 Mem_Free(vertexremap);
640 Mem_Free(shadowmark);
643 Mem_Free(shadowmarklist);
644 shadowmarklist = NULL;
649 Mem_Free(shadowsides);
652 Mem_Free(shadowsideslist);
653 shadowsideslist = NULL;
654 r_shadow_buffer_numleafpvsbytes = 0;
655 if (r_shadow_buffer_visitingleafpvs)
656 Mem_Free(r_shadow_buffer_visitingleafpvs);
657 r_shadow_buffer_visitingleafpvs = NULL;
658 if (r_shadow_buffer_leafpvs)
659 Mem_Free(r_shadow_buffer_leafpvs);
660 r_shadow_buffer_leafpvs = NULL;
661 if (r_shadow_buffer_leaflist)
662 Mem_Free(r_shadow_buffer_leaflist);
663 r_shadow_buffer_leaflist = NULL;
664 r_shadow_buffer_numsurfacepvsbytes = 0;
665 if (r_shadow_buffer_surfacepvs)
666 Mem_Free(r_shadow_buffer_surfacepvs);
667 r_shadow_buffer_surfacepvs = NULL;
668 if (r_shadow_buffer_surfacelist)
669 Mem_Free(r_shadow_buffer_surfacelist);
670 r_shadow_buffer_surfacelist = NULL;
671 if (r_shadow_buffer_surfacesides)
672 Mem_Free(r_shadow_buffer_surfacesides);
673 r_shadow_buffer_surfacesides = NULL;
674 r_shadow_buffer_numshadowtrispvsbytes = 0;
675 if (r_shadow_buffer_shadowtrispvs)
676 Mem_Free(r_shadow_buffer_shadowtrispvs);
677 r_shadow_buffer_numlighttrispvsbytes = 0;
678 if (r_shadow_buffer_lighttrispvs)
679 Mem_Free(r_shadow_buffer_lighttrispvs);
682 static void r_shadow_newmap(void)
684 if (r_shadow_bouncegridtexture) R_FreeTexture(r_shadow_bouncegridtexture);r_shadow_bouncegridtexture = NULL;
685 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
686 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
687 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
688 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
689 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
690 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
691 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
692 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
693 R_Shadow_EditLights_Reload_f();
696 void R_Shadow_Init(void)
698 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
699 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
700 Cvar_RegisterVariable(&r_shadow_usebihculling);
701 Cvar_RegisterVariable(&r_shadow_usenormalmap);
702 Cvar_RegisterVariable(&r_shadow_debuglight);
703 Cvar_RegisterVariable(&r_shadow_deferred);
704 Cvar_RegisterVariable(&r_shadow_gloss);
705 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
706 Cvar_RegisterVariable(&r_shadow_glossintensity);
707 Cvar_RegisterVariable(&r_shadow_glossexponent);
708 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
709 Cvar_RegisterVariable(&r_shadow_glossexact);
710 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
711 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
712 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
713 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
714 Cvar_RegisterVariable(&r_shadow_projectdistance);
715 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
716 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
717 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
718 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
719 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
720 Cvar_RegisterVariable(&r_shadow_realtime_world);
721 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
722 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
723 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
724 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
725 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
726 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
727 Cvar_RegisterVariable(&r_shadow_scissor);
728 Cvar_RegisterVariable(&r_shadow_shadowmapping);
729 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
730 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
731 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
732 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
733 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
734 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
735 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
736 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
737 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
738 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
739 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
740 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
741 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
742 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
743 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
744 Cvar_RegisterVariable(&r_shadow_polygonfactor);
745 Cvar_RegisterVariable(&r_shadow_polygonoffset);
746 Cvar_RegisterVariable(&r_shadow_texture3d);
747 Cvar_RegisterVariable(&r_shadow_bouncegrid);
748 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
749 Cvar_RegisterVariable(&r_shadow_bouncegrid_directionalshading);
750 Cvar_RegisterVariable(&r_shadow_bouncegrid_dlightparticlemultiplier);
751 Cvar_RegisterVariable(&r_shadow_bouncegrid_hitmodels);
752 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
753 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
754 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightradiusscale);
755 Cvar_RegisterVariable(&r_shadow_bouncegrid_maxbounce);
756 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
757 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
758 Cvar_RegisterVariable(&r_shadow_bouncegrid_photons);
759 Cvar_RegisterVariable(&r_shadow_bouncegrid_spacing);
760 Cvar_RegisterVariable(&r_shadow_bouncegrid_stablerandom);
761 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
762 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
763 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
764 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
765 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_photons);
766 Cvar_RegisterVariable(&r_shadow_bouncegrid_updateinterval);
767 Cvar_RegisterVariable(&r_shadow_bouncegrid_x);
768 Cvar_RegisterVariable(&r_shadow_bouncegrid_y);
769 Cvar_RegisterVariable(&r_shadow_bouncegrid_z);
770 Cvar_RegisterVariable(&r_coronas);
771 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
772 Cvar_RegisterVariable(&r_coronas_occlusionquery);
773 Cvar_RegisterVariable(&gl_flashblend);
774 Cvar_RegisterVariable(&gl_ext_separatestencil);
775 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
776 R_Shadow_EditLights_Init();
777 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
778 maxshadowtriangles = 0;
779 shadowelements = NULL;
780 maxshadowvertices = 0;
781 shadowvertex3f = NULL;
789 shadowmarklist = NULL;
794 shadowsideslist = NULL;
795 r_shadow_buffer_numleafpvsbytes = 0;
796 r_shadow_buffer_visitingleafpvs = NULL;
797 r_shadow_buffer_leafpvs = NULL;
798 r_shadow_buffer_leaflist = NULL;
799 r_shadow_buffer_numsurfacepvsbytes = 0;
800 r_shadow_buffer_surfacepvs = NULL;
801 r_shadow_buffer_surfacelist = NULL;
802 r_shadow_buffer_surfacesides = NULL;
803 r_shadow_buffer_shadowtrispvs = NULL;
804 r_shadow_buffer_lighttrispvs = NULL;
805 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
808 matrix4x4_t matrix_attenuationxyz =
811 {0.5, 0.0, 0.0, 0.5},
812 {0.0, 0.5, 0.0, 0.5},
813 {0.0, 0.0, 0.5, 0.5},
818 matrix4x4_t matrix_attenuationz =
821 {0.0, 0.0, 0.5, 0.5},
822 {0.0, 0.0, 0.0, 0.5},
823 {0.0, 0.0, 0.0, 0.5},
828 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
830 numvertices = ((numvertices + 255) & ~255) * vertscale;
831 numtriangles = ((numtriangles + 255) & ~255) * triscale;
832 // make sure shadowelements is big enough for this volume
833 if (maxshadowtriangles < numtriangles)
835 maxshadowtriangles = numtriangles;
837 Mem_Free(shadowelements);
838 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
840 // make sure shadowvertex3f is big enough for this volume
841 if (maxshadowvertices < numvertices)
843 maxshadowvertices = numvertices;
845 Mem_Free(shadowvertex3f);
846 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
850 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
852 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
853 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
854 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
855 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
856 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
858 if (r_shadow_buffer_visitingleafpvs)
859 Mem_Free(r_shadow_buffer_visitingleafpvs);
860 if (r_shadow_buffer_leafpvs)
861 Mem_Free(r_shadow_buffer_leafpvs);
862 if (r_shadow_buffer_leaflist)
863 Mem_Free(r_shadow_buffer_leaflist);
864 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
865 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
866 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
867 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
869 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
871 if (r_shadow_buffer_surfacepvs)
872 Mem_Free(r_shadow_buffer_surfacepvs);
873 if (r_shadow_buffer_surfacelist)
874 Mem_Free(r_shadow_buffer_surfacelist);
875 if (r_shadow_buffer_surfacesides)
876 Mem_Free(r_shadow_buffer_surfacesides);
877 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
878 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
879 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
880 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
882 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
884 if (r_shadow_buffer_shadowtrispvs)
885 Mem_Free(r_shadow_buffer_shadowtrispvs);
886 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
887 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
889 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
891 if (r_shadow_buffer_lighttrispvs)
892 Mem_Free(r_shadow_buffer_lighttrispvs);
893 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
894 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
898 void R_Shadow_PrepareShadowMark(int numtris)
900 // make sure shadowmark is big enough for this volume
901 if (maxshadowmark < numtris)
903 maxshadowmark = numtris;
905 Mem_Free(shadowmark);
907 Mem_Free(shadowmarklist);
908 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
909 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
913 // if shadowmarkcount wrapped we clear the array and adjust accordingly
914 if (shadowmarkcount == 0)
917 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
922 void R_Shadow_PrepareShadowSides(int numtris)
924 if (maxshadowsides < numtris)
926 maxshadowsides = numtris;
928 Mem_Free(shadowsides);
930 Mem_Free(shadowsideslist);
931 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
932 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
937 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)
940 int outtriangles = 0, outvertices = 0;
943 float ratio, direction[3], projectvector[3];
945 if (projectdirection)
946 VectorScale(projectdirection, projectdistance, projectvector);
948 VectorClear(projectvector);
950 // create the vertices
951 if (projectdirection)
953 for (i = 0;i < numshadowmarktris;i++)
955 element = inelement3i + shadowmarktris[i] * 3;
956 for (j = 0;j < 3;j++)
958 if (vertexupdate[element[j]] != vertexupdatenum)
960 vertexupdate[element[j]] = vertexupdatenum;
961 vertexremap[element[j]] = outvertices;
962 vertex = invertex3f + element[j] * 3;
963 // project one copy of the vertex according to projectvector
964 VectorCopy(vertex, outvertex3f);
965 VectorAdd(vertex, projectvector, (outvertex3f + 3));
974 for (i = 0;i < numshadowmarktris;i++)
976 element = inelement3i + shadowmarktris[i] * 3;
977 for (j = 0;j < 3;j++)
979 if (vertexupdate[element[j]] != vertexupdatenum)
981 vertexupdate[element[j]] = vertexupdatenum;
982 vertexremap[element[j]] = outvertices;
983 vertex = invertex3f + element[j] * 3;
984 // project one copy of the vertex to the sphere radius of the light
985 // (FIXME: would projecting it to the light box be better?)
986 VectorSubtract(vertex, projectorigin, direction);
987 ratio = projectdistance / VectorLength(direction);
988 VectorCopy(vertex, outvertex3f);
989 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
997 if (r_shadow_frontsidecasting.integer)
999 for (i = 0;i < numshadowmarktris;i++)
1001 int remappedelement[3];
1003 const int *neighbortriangle;
1005 markindex = shadowmarktris[i] * 3;
1006 element = inelement3i + markindex;
1007 neighbortriangle = inneighbor3i + markindex;
1008 // output the front and back triangles
1009 outelement3i[0] = vertexremap[element[0]];
1010 outelement3i[1] = vertexremap[element[1]];
1011 outelement3i[2] = vertexremap[element[2]];
1012 outelement3i[3] = vertexremap[element[2]] + 1;
1013 outelement3i[4] = vertexremap[element[1]] + 1;
1014 outelement3i[5] = vertexremap[element[0]] + 1;
1018 // output the sides (facing outward from this triangle)
1019 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1021 remappedelement[0] = vertexremap[element[0]];
1022 remappedelement[1] = vertexremap[element[1]];
1023 outelement3i[0] = remappedelement[1];
1024 outelement3i[1] = remappedelement[0];
1025 outelement3i[2] = remappedelement[0] + 1;
1026 outelement3i[3] = remappedelement[1];
1027 outelement3i[4] = remappedelement[0] + 1;
1028 outelement3i[5] = remappedelement[1] + 1;
1033 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1035 remappedelement[1] = vertexremap[element[1]];
1036 remappedelement[2] = vertexremap[element[2]];
1037 outelement3i[0] = remappedelement[2];
1038 outelement3i[1] = remappedelement[1];
1039 outelement3i[2] = remappedelement[1] + 1;
1040 outelement3i[3] = remappedelement[2];
1041 outelement3i[4] = remappedelement[1] + 1;
1042 outelement3i[5] = remappedelement[2] + 1;
1047 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1049 remappedelement[0] = vertexremap[element[0]];
1050 remappedelement[2] = vertexremap[element[2]];
1051 outelement3i[0] = remappedelement[0];
1052 outelement3i[1] = remappedelement[2];
1053 outelement3i[2] = remappedelement[2] + 1;
1054 outelement3i[3] = remappedelement[0];
1055 outelement3i[4] = remappedelement[2] + 1;
1056 outelement3i[5] = remappedelement[0] + 1;
1065 for (i = 0;i < numshadowmarktris;i++)
1067 int remappedelement[3];
1069 const int *neighbortriangle;
1071 markindex = shadowmarktris[i] * 3;
1072 element = inelement3i + markindex;
1073 neighbortriangle = inneighbor3i + markindex;
1074 // output the front and back triangles
1075 outelement3i[0] = vertexremap[element[2]];
1076 outelement3i[1] = vertexremap[element[1]];
1077 outelement3i[2] = vertexremap[element[0]];
1078 outelement3i[3] = vertexremap[element[0]] + 1;
1079 outelement3i[4] = vertexremap[element[1]] + 1;
1080 outelement3i[5] = vertexremap[element[2]] + 1;
1084 // output the sides (facing outward from this triangle)
1085 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1087 remappedelement[0] = vertexremap[element[0]];
1088 remappedelement[1] = vertexremap[element[1]];
1089 outelement3i[0] = remappedelement[0];
1090 outelement3i[1] = remappedelement[1];
1091 outelement3i[2] = remappedelement[1] + 1;
1092 outelement3i[3] = remappedelement[0];
1093 outelement3i[4] = remappedelement[1] + 1;
1094 outelement3i[5] = remappedelement[0] + 1;
1099 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1101 remappedelement[1] = vertexremap[element[1]];
1102 remappedelement[2] = vertexremap[element[2]];
1103 outelement3i[0] = remappedelement[1];
1104 outelement3i[1] = remappedelement[2];
1105 outelement3i[2] = remappedelement[2] + 1;
1106 outelement3i[3] = remappedelement[1];
1107 outelement3i[4] = remappedelement[2] + 1;
1108 outelement3i[5] = remappedelement[1] + 1;
1113 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1115 remappedelement[0] = vertexremap[element[0]];
1116 remappedelement[2] = vertexremap[element[2]];
1117 outelement3i[0] = remappedelement[2];
1118 outelement3i[1] = remappedelement[0];
1119 outelement3i[2] = remappedelement[0] + 1;
1120 outelement3i[3] = remappedelement[2];
1121 outelement3i[4] = remappedelement[0] + 1;
1122 outelement3i[5] = remappedelement[2] + 1;
1130 *outnumvertices = outvertices;
1131 return outtriangles;
1134 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)
1137 int outtriangles = 0, outvertices = 0;
1139 const float *vertex;
1140 float ratio, direction[3], projectvector[3];
1143 if (projectdirection)
1144 VectorScale(projectdirection, projectdistance, projectvector);
1146 VectorClear(projectvector);
1148 for (i = 0;i < numshadowmarktris;i++)
1150 int remappedelement[3];
1152 const int *neighbortriangle;
1154 markindex = shadowmarktris[i] * 3;
1155 neighbortriangle = inneighbor3i + markindex;
1156 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1157 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1158 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1159 if (side[0] + side[1] + side[2] == 0)
1163 element = inelement3i + markindex;
1165 // create the vertices
1166 for (j = 0;j < 3;j++)
1168 if (side[j] + side[j+1] == 0)
1171 if (vertexupdate[k] != vertexupdatenum)
1173 vertexupdate[k] = vertexupdatenum;
1174 vertexremap[k] = outvertices;
1175 vertex = invertex3f + k * 3;
1176 VectorCopy(vertex, outvertex3f);
1177 if (projectdirection)
1179 // project one copy of the vertex according to projectvector
1180 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1184 // project one copy of the vertex to the sphere radius of the light
1185 // (FIXME: would projecting it to the light box be better?)
1186 VectorSubtract(vertex, projectorigin, direction);
1187 ratio = projectdistance / VectorLength(direction);
1188 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1195 // output the sides (facing outward from this triangle)
1198 remappedelement[0] = vertexremap[element[0]];
1199 remappedelement[1] = vertexremap[element[1]];
1200 outelement3i[0] = remappedelement[1];
1201 outelement3i[1] = remappedelement[0];
1202 outelement3i[2] = remappedelement[0] + 1;
1203 outelement3i[3] = remappedelement[1];
1204 outelement3i[4] = remappedelement[0] + 1;
1205 outelement3i[5] = remappedelement[1] + 1;
1212 remappedelement[1] = vertexremap[element[1]];
1213 remappedelement[2] = vertexremap[element[2]];
1214 outelement3i[0] = remappedelement[2];
1215 outelement3i[1] = remappedelement[1];
1216 outelement3i[2] = remappedelement[1] + 1;
1217 outelement3i[3] = remappedelement[2];
1218 outelement3i[4] = remappedelement[1] + 1;
1219 outelement3i[5] = remappedelement[2] + 1;
1226 remappedelement[0] = vertexremap[element[0]];
1227 remappedelement[2] = vertexremap[element[2]];
1228 outelement3i[0] = remappedelement[0];
1229 outelement3i[1] = remappedelement[2];
1230 outelement3i[2] = remappedelement[2] + 1;
1231 outelement3i[3] = remappedelement[0];
1232 outelement3i[4] = remappedelement[2] + 1;
1233 outelement3i[5] = remappedelement[0] + 1;
1240 *outnumvertices = outvertices;
1241 return outtriangles;
1244 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)
1250 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1252 tend = firsttriangle + numtris;
1253 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1255 // surface box entirely inside light box, no box cull
1256 if (projectdirection)
1258 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1260 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1261 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1262 shadowmarklist[numshadowmark++] = t;
1267 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1268 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1269 shadowmarklist[numshadowmark++] = t;
1274 // surface box not entirely inside light box, cull each triangle
1275 if (projectdirection)
1277 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1279 v[0] = invertex3f + e[0] * 3;
1280 v[1] = invertex3f + e[1] * 3;
1281 v[2] = invertex3f + e[2] * 3;
1282 TriangleNormal(v[0], v[1], v[2], normal);
1283 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1284 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1285 shadowmarklist[numshadowmark++] = t;
1290 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1292 v[0] = invertex3f + e[0] * 3;
1293 v[1] = invertex3f + e[1] * 3;
1294 v[2] = invertex3f + e[2] * 3;
1295 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1296 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1297 shadowmarklist[numshadowmark++] = t;
1303 static qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1308 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1310 // check if the shadow volume intersects the near plane
1312 // a ray between the eye and light origin may intersect the caster,
1313 // indicating that the shadow may touch the eye location, however we must
1314 // test the near plane (a polygon), not merely the eye location, so it is
1315 // easiest to enlarge the caster bounding shape slightly for this.
1321 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)
1323 int i, tris, outverts;
1324 if (projectdistance < 0.1)
1326 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1329 if (!numverts || !nummarktris)
1331 // make sure shadowelements is big enough for this volume
1332 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1333 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1335 if (maxvertexupdate < numverts)
1337 maxvertexupdate = numverts;
1339 Mem_Free(vertexupdate);
1341 Mem_Free(vertexremap);
1342 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1343 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1344 vertexupdatenum = 0;
1347 if (vertexupdatenum == 0)
1349 vertexupdatenum = 1;
1350 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1351 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1354 for (i = 0;i < nummarktris;i++)
1355 shadowmark[marktris[i]] = shadowmarkcount;
1357 if (r_shadow_compilingrtlight)
1359 // if we're compiling an rtlight, capture the mesh
1360 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1361 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1362 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1363 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1365 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1367 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1368 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1369 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1373 // decide which type of shadow to generate and set stencil mode
1374 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1375 // generate the sides or a solid volume, depending on type
1376 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1377 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1379 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1380 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1381 r_refdef.stats.lights_shadowtriangles += tris;
1382 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1384 // increment stencil if frontface is infront of depthbuffer
1385 GL_CullFace(r_refdef.view.cullface_front);
1386 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1387 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1388 // decrement stencil if backface is infront of depthbuffer
1389 GL_CullFace(r_refdef.view.cullface_back);
1390 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1392 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1394 // decrement stencil if backface is behind depthbuffer
1395 GL_CullFace(r_refdef.view.cullface_front);
1396 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1397 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1398 // increment stencil if frontface is behind depthbuffer
1399 GL_CullFace(r_refdef.view.cullface_back);
1400 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1402 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1403 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1407 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1409 // p1, p2, p3 are in the cubemap's local coordinate system
1410 // bias = border/(size - border)
1413 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1414 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1415 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1416 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1418 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1419 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1420 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1421 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1423 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1424 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1425 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1427 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1428 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1429 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1430 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1432 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1433 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1434 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1435 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1437 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1438 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1439 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1441 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1442 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1443 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1444 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1446 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1447 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1448 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1449 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1451 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1452 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1453 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1458 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1460 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1461 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1464 VectorSubtract(maxs, mins, radius);
1465 VectorScale(radius, 0.5f, radius);
1466 VectorAdd(mins, radius, center);
1467 Matrix4x4_Transform(worldtolight, center, lightcenter);
1468 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1469 VectorSubtract(lightcenter, lightradius, pmin);
1470 VectorAdd(lightcenter, lightradius, pmax);
1472 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1473 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1474 if(ap1 > bias*an1 && ap2 > bias*an2)
1476 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1477 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1478 if(an1 > bias*ap1 && an2 > bias*ap2)
1480 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1481 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1483 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1484 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1485 if(ap1 > bias*an1 && ap2 > bias*an2)
1487 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1488 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1489 if(an1 > bias*ap1 && an2 > bias*ap2)
1491 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1492 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1494 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1495 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1496 if(ap1 > bias*an1 && ap2 > bias*an2)
1498 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1499 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1500 if(an1 > bias*ap1 && an2 > bias*ap2)
1502 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1503 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1508 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1510 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1512 // p is in the cubemap's local coordinate system
1513 // bias = border/(size - border)
1514 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1515 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1516 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1518 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1519 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1520 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1521 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1522 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1523 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1527 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1531 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1532 float scale = (size - 2*border)/size, len;
1533 float bias = border / (float)(size - border), dp, dn, ap, an;
1534 // check if cone enclosing side would cross frustum plane
1535 scale = 2 / (scale*scale + 2);
1536 for (i = 0;i < 5;i++)
1538 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1540 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1541 len = scale*VectorLength2(n);
1542 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1543 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1544 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1546 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1548 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1549 len = scale*VectorLength(n);
1550 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1551 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1552 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1554 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1555 // check if frustum corners/origin cross plane sides
1557 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1558 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1559 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1560 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1561 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1562 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1563 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1564 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1565 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1566 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1567 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1568 for (i = 0;i < 4;i++)
1570 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1571 VectorSubtract(n, p, n);
1572 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1573 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1574 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1575 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1576 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1577 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1578 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1579 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1580 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1583 // finite version, assumes corners are a finite distance from origin dependent on far plane
1584 for (i = 0;i < 5;i++)
1586 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1587 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1588 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1589 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1590 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1591 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1592 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1593 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1594 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1595 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1598 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1601 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)
1609 int mask, surfacemask = 0;
1610 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1612 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1613 tend = firsttriangle + numtris;
1614 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1616 // surface box entirely inside light box, no box cull
1617 if (projectdirection)
1619 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1621 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1622 TriangleNormal(v[0], v[1], v[2], normal);
1623 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1625 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1626 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1627 surfacemask |= mask;
1630 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;
1631 shadowsides[numshadowsides] = mask;
1632 shadowsideslist[numshadowsides++] = t;
1639 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1641 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1642 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1644 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1645 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1646 surfacemask |= mask;
1649 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;
1650 shadowsides[numshadowsides] = mask;
1651 shadowsideslist[numshadowsides++] = t;
1659 // surface box not entirely inside light box, cull each triangle
1660 if (projectdirection)
1662 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1664 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1665 TriangleNormal(v[0], v[1], v[2], normal);
1666 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1667 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1669 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1670 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1671 surfacemask |= mask;
1674 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;
1675 shadowsides[numshadowsides] = mask;
1676 shadowsideslist[numshadowsides++] = t;
1683 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1685 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1686 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1687 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1689 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1690 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1691 surfacemask |= mask;
1694 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;
1695 shadowsides[numshadowsides] = mask;
1696 shadowsideslist[numshadowsides++] = t;
1705 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)
1707 int i, j, outtriangles = 0;
1708 int *outelement3i[6];
1709 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1711 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1712 // make sure shadowelements is big enough for this mesh
1713 if (maxshadowtriangles < outtriangles)
1714 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1716 // compute the offset and size of the separate index lists for each cubemap side
1718 for (i = 0;i < 6;i++)
1720 outelement3i[i] = shadowelements + outtriangles * 3;
1721 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1722 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1723 outtriangles += sidetotals[i];
1726 // gather up the (sparse) triangles into separate index lists for each cubemap side
1727 for (i = 0;i < numsidetris;i++)
1729 const int *element = elements + sidetris[i] * 3;
1730 for (j = 0;j < 6;j++)
1732 if (sides[i] & (1 << j))
1734 outelement3i[j][0] = element[0];
1735 outelement3i[j][1] = element[1];
1736 outelement3i[j][2] = element[2];
1737 outelement3i[j] += 3;
1742 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1745 static void R_Shadow_MakeTextures_MakeCorona(void)
1749 unsigned char pixels[32][32][4];
1750 for (y = 0;y < 32;y++)
1752 dy = (y - 15.5f) * (1.0f / 16.0f);
1753 for (x = 0;x < 32;x++)
1755 dx = (x - 15.5f) * (1.0f / 16.0f);
1756 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1757 a = bound(0, a, 255);
1758 pixels[y][x][0] = a;
1759 pixels[y][x][1] = a;
1760 pixels[y][x][2] = a;
1761 pixels[y][x][3] = 255;
1764 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, false);
1767 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1769 float dist = sqrt(x*x+y*y+z*z);
1770 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1771 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1772 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1775 static void R_Shadow_MakeTextures(void)
1778 float intensity, dist;
1780 R_Shadow_FreeShadowMaps();
1781 R_FreeTexturePool(&r_shadow_texturepool);
1782 r_shadow_texturepool = R_AllocTexturePool();
1783 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1784 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1785 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1786 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1787 for (x = 0;x <= ATTENTABLESIZE;x++)
1789 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1790 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1791 r_shadow_attentable[x] = bound(0, intensity, 1);
1793 // 1D gradient texture
1794 for (x = 0;x < ATTEN1DSIZE;x++)
1795 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1796 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1797 // 2D circle texture
1798 for (y = 0;y < ATTEN2DSIZE;y++)
1799 for (x = 0;x < ATTEN2DSIZE;x++)
1800 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);
1801 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1802 // 3D sphere texture
1803 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1805 for (z = 0;z < ATTEN3DSIZE;z++)
1806 for (y = 0;y < ATTEN3DSIZE;y++)
1807 for (x = 0;x < ATTEN3DSIZE;x++)
1808 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));
1809 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);
1812 r_shadow_attenuation3dtexture = NULL;
1815 R_Shadow_MakeTextures_MakeCorona();
1817 // Editor light sprites
1818 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1835 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1836 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1853 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1854 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1871 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1872 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1889 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1890 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1907 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1908 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1925 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1928 void R_Shadow_ValidateCvars(void)
1930 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1931 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1932 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1933 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1934 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1935 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1938 void R_Shadow_RenderMode_Begin(void)
1944 R_Shadow_ValidateCvars();
1946 if (!r_shadow_attenuation2dtexture
1947 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1948 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1949 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1950 R_Shadow_MakeTextures();
1953 R_Mesh_ResetTextureState();
1954 GL_BlendFunc(GL_ONE, GL_ZERO);
1955 GL_DepthRange(0, 1);
1956 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1958 GL_DepthMask(false);
1959 GL_Color(0, 0, 0, 1);
1960 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1962 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1964 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1966 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1967 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1969 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1971 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1972 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1976 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1977 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1980 switch(vid.renderpath)
1982 case RENDERPATH_GL20:
1983 case RENDERPATH_D3D9:
1984 case RENDERPATH_D3D10:
1985 case RENDERPATH_D3D11:
1986 case RENDERPATH_SOFT:
1987 case RENDERPATH_GLES2:
1988 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1990 case RENDERPATH_GL11:
1991 case RENDERPATH_GL13:
1992 case RENDERPATH_GLES1:
1993 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1994 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1995 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1996 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1997 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1998 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
2000 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
2006 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
2007 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
2008 r_shadow_drawbuffer = drawbuffer;
2009 r_shadow_readbuffer = readbuffer;
2011 r_shadow_cullface_front = r_refdef.view.cullface_front;
2012 r_shadow_cullface_back = r_refdef.view.cullface_back;
2015 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
2017 rsurface.rtlight = rtlight;
2020 void R_Shadow_RenderMode_Reset(void)
2022 R_Mesh_ResetTextureState();
2023 R_Mesh_SetRenderTargets(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture, NULL, NULL, NULL);
2024 R_SetViewport(&r_refdef.view.viewport);
2025 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
2026 GL_DepthRange(0, 1);
2028 GL_DepthMask(false);
2029 GL_DepthFunc(GL_LEQUAL);
2030 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2031 r_refdef.view.cullface_front = r_shadow_cullface_front;
2032 r_refdef.view.cullface_back = r_shadow_cullface_back;
2033 GL_CullFace(r_refdef.view.cullface_back);
2034 GL_Color(1, 1, 1, 1);
2035 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2036 GL_BlendFunc(GL_ONE, GL_ZERO);
2037 R_SetupShader_Generic_NoTexture(false, false);
2038 r_shadow_usingshadowmap2d = false;
2039 r_shadow_usingshadowmaportho = false;
2040 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2043 void R_Shadow_ClearStencil(void)
2045 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2046 r_refdef.stats.lights_clears++;
2049 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2051 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2052 if (r_shadow_rendermode == mode)
2054 R_Shadow_RenderMode_Reset();
2055 GL_DepthFunc(GL_LESS);
2056 GL_ColorMask(0, 0, 0, 0);
2057 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2058 GL_CullFace(GL_NONE);
2059 R_SetupShader_DepthOrShadow(false, false);
2060 r_shadow_rendermode = mode;
2065 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2066 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2067 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2069 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2070 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2071 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2076 static void R_Shadow_MakeVSDCT(void)
2078 // maps to a 2x3 texture rectangle with normalized coordinates
2083 // stores abs(dir.xy), offset.xy/2.5
2084 unsigned char data[4*6] =
2086 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2087 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2088 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2089 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2090 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2091 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2093 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2096 static void R_Shadow_MakeShadowMap(int side, int size)
2098 switch (r_shadow_shadowmode)
2100 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2101 if (r_shadow_shadowmap2ddepthtexture) return;
2102 if (r_fb.usedepthtextures)
2104 r_shadow_shadowmap2ddepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), r_shadow_shadowmapdepthbits >= 24 ? (r_shadow_shadowmapsampler ? TEXTYPE_SHADOWMAP24_COMP : TEXTYPE_SHADOWMAP24_RAW) : (r_shadow_shadowmapsampler ? TEXTYPE_SHADOWMAP16_COMP : TEXTYPE_SHADOWMAP16_RAW), false);
2105 r_shadow_shadowmap2ddepthbuffer = NULL;
2106 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2110 r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2111 r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
2112 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2120 static void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2122 float nearclip, farclip, bias;
2123 r_viewport_t viewport;
2126 float clearcolor[4];
2127 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2129 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2130 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2131 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2132 r_shadow_shadowmapside = side;
2133 r_shadow_shadowmapsize = size;
2135 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2136 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2137 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2138 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2140 // complex unrolled cube approach (more flexible)
2141 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2142 R_Shadow_MakeVSDCT();
2143 if (!r_shadow_shadowmap2ddepthtexture)
2144 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2145 fbo2d = r_shadow_fbo2d;
2146 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
2147 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
2148 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2150 R_Mesh_ResetTextureState();
2151 R_Shadow_RenderMode_Reset();
2152 if (r_shadow_shadowmap2ddepthbuffer)
2153 R_Mesh_SetRenderTargets(fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2155 R_Mesh_SetRenderTargets(fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2156 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL);
2157 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2162 R_SetViewport(&viewport);
2163 flipped = (side & 1) ^ (side >> 2);
2164 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2165 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2166 if (r_shadow_shadowmap2ddepthbuffer)
2168 // completely different meaning than in depthtexture approach
2169 r_shadow_shadowmap_parameters[1] = 0;
2170 r_shadow_shadowmap_parameters[3] = -bias;
2172 Vector4Set(clearcolor, 1,1,1,1);
2173 if (r_shadow_shadowmap2ddepthbuffer)
2174 GL_ColorMask(1,1,1,1);
2176 GL_ColorMask(0,0,0,0);
2177 switch(vid.renderpath)
2179 case RENDERPATH_GL11:
2180 case RENDERPATH_GL13:
2181 case RENDERPATH_GL20:
2182 case RENDERPATH_SOFT:
2183 case RENDERPATH_GLES1:
2184 case RENDERPATH_GLES2:
2185 GL_CullFace(r_refdef.view.cullface_back);
2186 // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
2187 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2189 // get tightest scissor rectangle that encloses all viewports in the clear mask
2190 int x1 = clear & 0x15 ? 0 : size;
2191 int x2 = clear & 0x2A ? 2 * size : size;
2192 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2193 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2194 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2197 if (r_shadow_shadowmap2ddepthbuffer)
2198 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2200 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2203 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2205 case RENDERPATH_D3D9:
2206 case RENDERPATH_D3D10:
2207 case RENDERPATH_D3D11:
2208 // we invert the cull mode because we flip the projection matrix
2209 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2210 GL_CullFace(r_refdef.view.cullface_front);
2211 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2212 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2215 if (r_shadow_shadowmap2ddepthbuffer)
2216 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2218 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2224 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2226 R_Mesh_ResetTextureState();
2229 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2230 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2231 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2232 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2234 R_Shadow_RenderMode_Reset();
2235 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2237 GL_DepthFunc(GL_EQUAL);
2238 // do global setup needed for the chosen lighting mode
2239 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2240 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2241 r_shadow_usingshadowmap2d = shadowmapping;
2242 r_shadow_rendermode = r_shadow_lightingrendermode;
2243 // only draw light where this geometry was already rendered AND the
2244 // stencil is 128 (values other than this mean shadow)
2246 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2248 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2251 static const unsigned short bboxelements[36] =
2261 static const float bboxpoints[8][3] =
2273 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2276 float vertex3f[8*3];
2277 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2278 // do global setup needed for the chosen lighting mode
2279 R_Shadow_RenderMode_Reset();
2280 r_shadow_rendermode = r_shadow_lightingrendermode;
2281 R_EntityMatrix(&identitymatrix);
2282 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2283 // only draw light where this geometry was already rendered AND the
2284 // stencil is 128 (values other than this mean shadow)
2285 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2286 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
2287 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2289 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
2291 r_shadow_usingshadowmap2d = shadowmapping;
2293 // render the lighting
2294 R_SetupShader_DeferredLight(rsurface.rtlight);
2295 for (i = 0;i < 8;i++)
2296 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2297 GL_ColorMask(1,1,1,1);
2298 GL_DepthMask(false);
2299 GL_DepthRange(0, 1);
2300 GL_PolygonOffset(0, 0);
2302 GL_DepthFunc(GL_GREATER);
2303 GL_CullFace(r_refdef.view.cullface_back);
2304 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL);
2305 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2308 void R_Shadow_UpdateBounceGridTexture(void)
2310 #define MAXBOUNCEGRIDPARTICLESPERLIGHT 1048576
2312 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2314 int hitsupercontentsmask;
2323 //trace_t cliptrace2;
2324 //trace_t cliptrace3;
2325 unsigned char *pixel;
2326 unsigned char *pixels;
2329 unsigned int lightindex;
2331 unsigned int range1;
2332 unsigned int range2;
2333 unsigned int seed = (unsigned int)(realtime * 1000.0f);
2335 vec3_t baseshotcolor;
2348 vec3_t cullmins, cullmaxs;
2351 vec_t lightintensity;
2352 vec_t photonscaling;
2353 vec_t photonresidual;
2355 float texlerp[2][3];
2356 float splatcolor[32];
2357 float pixelweight[8];
2369 r_shadow_bouncegrid_settings_t settings;
2370 qboolean enable = r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
2371 qboolean allowdirectionalshading = false;
2372 switch(vid.renderpath)
2374 case RENDERPATH_GL20:
2375 allowdirectionalshading = true;
2376 if (!vid.support.ext_texture_3d)
2379 case RENDERPATH_GLES2:
2380 // for performance reasons, do not use directional shading on GLES devices
2381 if (!vid.support.ext_texture_3d)
2384 // these renderpaths do not currently have the code to display the bouncegrid, so disable it on them...
2385 case RENDERPATH_GL11:
2386 case RENDERPATH_GL13:
2387 case RENDERPATH_GLES1:
2388 case RENDERPATH_SOFT:
2389 case RENDERPATH_D3D9:
2390 case RENDERPATH_D3D10:
2391 case RENDERPATH_D3D11:
2395 r_shadow_bouncegridintensity = r_shadow_bouncegrid_intensity.value;
2397 // see if there are really any lights to render...
2398 if (enable && r_shadow_bouncegrid_static.integer)
2401 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2402 for (lightindex = 0;lightindex < range;lightindex++)
2404 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2405 if (!light || !(light->flags & flag))
2407 rtlight = &light->rtlight;
2408 // when static, we skip styled lights because they tend to change...
2409 if (rtlight->style > 0)
2411 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
2412 if (!VectorLength2(lightcolor))
2421 if (r_shadow_bouncegridtexture)
2423 R_FreeTexture(r_shadow_bouncegridtexture);
2424 r_shadow_bouncegridtexture = NULL;
2426 if (r_shadow_bouncegridpixels)
2427 Mem_Free(r_shadow_bouncegridpixels);
2428 r_shadow_bouncegridpixels = NULL;
2429 if (r_shadow_bouncegridhighpixels)
2430 Mem_Free(r_shadow_bouncegridhighpixels);
2431 r_shadow_bouncegridhighpixels = NULL;
2432 r_shadow_bouncegridnumpixels = 0;
2433 r_shadow_bouncegriddirectional = false;
2437 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
2438 memset(&settings, 0, sizeof(settings));
2439 settings.staticmode = r_shadow_bouncegrid_static.integer != 0;
2440 settings.bounceanglediffuse = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
2441 settings.directionalshading = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_directionalshading.integer != 0) && allowdirectionalshading;
2442 settings.dlightparticlemultiplier = r_shadow_bouncegrid_dlightparticlemultiplier.value;
2443 settings.hitmodels = r_shadow_bouncegrid_hitmodels.integer != 0;
2444 settings.includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
2445 settings.lightradiusscale = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_lightradiusscale.value);
2446 settings.maxbounce = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_maxbounce.integer);
2447 settings.particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
2448 settings.particleintensity = r_shadow_bouncegrid_particleintensity.value * 16384.0f * (settings.directionalshading ? 4.0f : 1.0f) / (r_shadow_bouncegrid_spacing.value * r_shadow_bouncegrid_spacing.value);
2449 settings.photons = r_shadow_bouncegrid_static.integer ? r_shadow_bouncegrid_static_photons.integer : r_shadow_bouncegrid_photons.integer;
2450 settings.spacing[0] = r_shadow_bouncegrid_spacing.value;
2451 settings.spacing[1] = r_shadow_bouncegrid_spacing.value;
2452 settings.spacing[2] = r_shadow_bouncegrid_spacing.value;
2453 settings.stablerandom = r_shadow_bouncegrid_stablerandom.integer;
2455 // bound the values for sanity
2456 settings.photons = bound(1, settings.photons, 1048576);
2457 settings.lightradiusscale = bound(0.0001f, settings.lightradiusscale, 1024.0f);
2458 settings.maxbounce = bound(0, settings.maxbounce, 16);
2459 settings.spacing[0] = bound(1, settings.spacing[0], 512);
2460 settings.spacing[1] = bound(1, settings.spacing[1], 512);
2461 settings.spacing[2] = bound(1, settings.spacing[2], 512);
2463 // get the spacing values
2464 spacing[0] = settings.spacing[0];
2465 spacing[1] = settings.spacing[1];
2466 spacing[2] = settings.spacing[2];
2467 ispacing[0] = 1.0f / spacing[0];
2468 ispacing[1] = 1.0f / spacing[1];
2469 ispacing[2] = 1.0f / spacing[2];
2471 // calculate texture size enclosing entire world bounds at the spacing
2472 VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
2473 VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
2474 VectorSubtract(maxs, mins, size);
2475 // now we can calculate the resolution we want
2476 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2477 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2478 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2479 // figure out the exact texture size (honoring power of 2 if required)
2480 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2481 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2482 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2483 if (vid.support.arb_texture_non_power_of_two)
2485 resolution[0] = c[0];
2486 resolution[1] = c[1];
2487 resolution[2] = c[2];
2491 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2492 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2493 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2495 size[0] = spacing[0] * resolution[0];
2496 size[1] = spacing[1] * resolution[1];
2497 size[2] = spacing[2] * resolution[2];
2499 // if dynamic we may or may not want to use the world bounds
2500 // if the dynamic size is smaller than the world bounds, use it instead
2501 if (!settings.staticmode && (r_shadow_bouncegrid_x.integer * r_shadow_bouncegrid_y.integer * r_shadow_bouncegrid_z.integer < resolution[0] * resolution[1] * resolution[2]))
2503 // we know the resolution we want
2504 c[0] = r_shadow_bouncegrid_x.integer;
2505 c[1] = r_shadow_bouncegrid_y.integer;
2506 c[2] = r_shadow_bouncegrid_z.integer;
2507 // now we can calculate the texture size (power of 2 if required)
2508 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2509 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2510 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2511 if (vid.support.arb_texture_non_power_of_two)
2513 resolution[0] = c[0];
2514 resolution[1] = c[1];
2515 resolution[2] = c[2];
2519 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2520 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2521 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2523 size[0] = spacing[0] * resolution[0];
2524 size[1] = spacing[1] * resolution[1];
2525 size[2] = spacing[2] * resolution[2];
2526 // center the rendering on the view
2527 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2528 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2529 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2532 // recalculate the maxs in case the resolution was not satisfactory
2533 VectorAdd(mins, size, maxs);
2535 // if all the settings seem identical to the previous update, return
2536 if (r_shadow_bouncegridtexture && (settings.staticmode || realtime < r_shadow_bouncegridtime + r_shadow_bouncegrid_updateinterval.value) && !memcmp(&r_shadow_bouncegridsettings, &settings, sizeof(settings)))
2539 // store the new settings
2540 r_shadow_bouncegridsettings = settings;
2542 pixelbands = settings.directionalshading ? 8 : 1;
2543 pixelsperband = resolution[0]*resolution[1]*resolution[2];
2544 numpixels = pixelsperband*pixelbands;
2546 // we're going to update the bouncegrid, update the matrix...
2547 memset(m, 0, sizeof(m));
2548 m[0] = 1.0f / size[0];
2549 m[3] = -mins[0] * m[0];
2550 m[5] = 1.0f / size[1];
2551 m[7] = -mins[1] * m[5];
2552 m[10] = 1.0f / size[2];
2553 m[11] = -mins[2] * m[10];
2555 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegridmatrix, m);
2556 // reallocate pixels for this update if needed...
2557 if (r_shadow_bouncegridnumpixels != numpixels || !r_shadow_bouncegridpixels || !r_shadow_bouncegridhighpixels)
2559 if (r_shadow_bouncegridtexture)
2561 R_FreeTexture(r_shadow_bouncegridtexture);
2562 r_shadow_bouncegridtexture = NULL;
2564 r_shadow_bouncegridpixels = (unsigned char *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridpixels, numpixels * sizeof(unsigned char[4]));
2565 r_shadow_bouncegridhighpixels = (float *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridhighpixels, numpixels * sizeof(float[4]));
2567 r_shadow_bouncegridnumpixels = numpixels;
2568 pixels = r_shadow_bouncegridpixels;
2569 highpixels = r_shadow_bouncegridhighpixels;
2570 x = pixelsperband*4;
2571 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2574 memset(pixels + pixelband * x, 128, x);
2576 memset(pixels + pixelband * x, 0, x);
2578 memset(highpixels, 0, numpixels * sizeof(float[4]));
2579 // figure out what we want to interact with
2580 if (settings.hitmodels)
2581 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;// | SUPERCONTENTS_LIQUIDSMASK;
2583 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
2584 maxbounce = settings.maxbounce;
2585 // clear variables that produce warnings otherwise
2586 memset(splatcolor, 0, sizeof(splatcolor));
2587 // iterate world rtlights
2588 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2589 range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
2590 range2 = range + range1;
2592 for (lightindex = 0;lightindex < range2;lightindex++)
2594 if (lightindex < range)
2596 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2599 rtlight = &light->rtlight;
2600 VectorClear(rtlight->photoncolor);
2601 rtlight->photons = 0;
2602 if (!(light->flags & flag))
2604 if (settings.staticmode)
2606 // when static, we skip styled lights because they tend to change...
2607 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2613 rtlight = r_refdef.scene.lights[lightindex - range];
2614 VectorClear(rtlight->photoncolor);
2615 rtlight->photons = 0;
2617 // draw only visible lights (major speedup)
2618 radius = rtlight->radius * settings.lightradiusscale;
2619 cullmins[0] = rtlight->shadoworigin[0] - radius;
2620 cullmins[1] = rtlight->shadoworigin[1] - radius;
2621 cullmins[2] = rtlight->shadoworigin[2] - radius;
2622 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2623 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2624 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2625 if (R_CullBox(cullmins, cullmaxs))
2627 if (r_refdef.scene.worldmodel
2628 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2629 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2631 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2632 if (w * VectorLength2(rtlight->color) == 0.0f)
2634 w *= (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2635 VectorScale(rtlight->color, w, rtlight->photoncolor);
2636 //if (!VectorLength2(rtlight->photoncolor))
2638 // shoot particles from this light
2639 // use a calculation for the number of particles that will not
2640 // vary with lightstyle, otherwise we get randomized particle
2641 // distribution, the seeded random is only consistent for a
2642 // consistent number of particles on this light...
2643 s = rtlight->radius;
2644 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2645 if (lightindex >= range)
2646 lightintensity *= settings.dlightparticlemultiplier;
2647 rtlight->photons = max(0.0f, lightintensity * s * s);
2648 photoncount += rtlight->photons;
2650 photonscaling = (float)settings.photons / max(1, photoncount);
2651 photonresidual = 0.0f;
2652 for (lightindex = 0;lightindex < range2;lightindex++)
2654 if (lightindex < range)
2656 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2659 rtlight = &light->rtlight;
2662 rtlight = r_refdef.scene.lights[lightindex - range];
2663 // skip a light with no photons
2664 if (rtlight->photons == 0.0f)
2666 // skip a light with no photon color)
2667 if (VectorLength2(rtlight->photoncolor) == 0.0f)
2669 photonresidual += rtlight->photons * photonscaling;
2670 shootparticles = (int)bound(0, photonresidual, MAXBOUNCEGRIDPARTICLESPERLIGHT);
2671 if (!shootparticles)
2673 photonresidual -= shootparticles;
2674 radius = rtlight->radius * settings.lightradiusscale;
2675 s = settings.particleintensity / shootparticles;
2676 VectorScale(rtlight->photoncolor, s, baseshotcolor);
2677 r_refdef.stats.bouncegrid_lights++;
2678 r_refdef.stats.bouncegrid_particles += shootparticles;
2679 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2681 if (settings.stablerandom > 0)
2682 seed = lightindex * 11937 + shotparticles;
2683 VectorCopy(baseshotcolor, shotcolor);
2684 VectorCopy(rtlight->shadoworigin, clipstart);
2685 if (settings.stablerandom < 0)
2686 VectorRandom(clipend);
2688 VectorCheeseRandom(clipend);
2689 VectorMA(clipstart, radius, clipend, clipend);
2690 for (bouncecount = 0;;bouncecount++)
2692 r_refdef.stats.bouncegrid_traces++;
2693 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2694 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2695 if (settings.staticmode)
2697 // static mode fires a LOT of rays but none of them are identical, so they are not cached
2698 cliptrace = CL_TraceLine(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), NULL, hitsupercontentsmask, true, false, NULL, true, true);
2702 // dynamic mode fires many rays and most will match the cache from the previous frame
2703 cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask);
2705 if (bouncecount > 0 || settings.includedirectlighting)
2707 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2708 // accumulate average shotcolor
2709 w = VectorLength(shotcolor);
2710 splatcolor[ 0] = shotcolor[0];
2711 splatcolor[ 1] = shotcolor[1];
2712 splatcolor[ 2] = shotcolor[2];
2713 splatcolor[ 3] = 0.0f;
2716 VectorSubtract(clipstart, cliptrace.endpos, clipdiff);
2717 VectorNormalize(clipdiff);
2718 // store bentnormal in case the shader has a use for it
2719 splatcolor[ 4] = clipdiff[0] * w;
2720 splatcolor[ 5] = clipdiff[1] * w;
2721 splatcolor[ 6] = clipdiff[2] * w;
2723 // accumulate directional contributions (+X, +Y, +Z, -X, -Y, -Z)
2724 splatcolor[ 8] = shotcolor[0] * max(0.0f, clipdiff[0]);
2725 splatcolor[ 9] = shotcolor[0] * max(0.0f, clipdiff[1]);
2726 splatcolor[10] = shotcolor[0] * max(0.0f, clipdiff[2]);
2727 splatcolor[11] = 0.0f;
2728 splatcolor[12] = shotcolor[1] * max(0.0f, clipdiff[0]);
2729 splatcolor[13] = shotcolor[1] * max(0.0f, clipdiff[1]);
2730 splatcolor[14] = shotcolor[1] * max(0.0f, clipdiff[2]);
2731 splatcolor[15] = 0.0f;
2732 splatcolor[16] = shotcolor[2] * max(0.0f, clipdiff[0]);
2733 splatcolor[17] = shotcolor[2] * max(0.0f, clipdiff[1]);
2734 splatcolor[18] = shotcolor[2] * max(0.0f, clipdiff[2]);
2735 splatcolor[19] = 0.0f;
2736 splatcolor[20] = shotcolor[0] * max(0.0f, -clipdiff[0]);
2737 splatcolor[21] = shotcolor[0] * max(0.0f, -clipdiff[1]);
2738 splatcolor[22] = shotcolor[0] * max(0.0f, -clipdiff[2]);
2739 splatcolor[23] = 0.0f;
2740 splatcolor[24] = shotcolor[1] * max(0.0f, -clipdiff[0]);
2741 splatcolor[25] = shotcolor[1] * max(0.0f, -clipdiff[1]);
2742 splatcolor[26] = shotcolor[1] * max(0.0f, -clipdiff[2]);
2743 splatcolor[27] = 0.0f;
2744 splatcolor[28] = shotcolor[2] * max(0.0f, -clipdiff[0]);
2745 splatcolor[29] = shotcolor[2] * max(0.0f, -clipdiff[1]);
2746 splatcolor[30] = shotcolor[2] * max(0.0f, -clipdiff[2]);
2747 splatcolor[31] = 0.0f;
2749 // calculate the number of steps we need to traverse this distance
2750 VectorSubtract(cliptrace.endpos, clipstart, stepdelta);
2751 numsteps = (int)(VectorLength(stepdelta) * ispacing[0]);
2752 numsteps = bound(1, numsteps, 1024);
2753 w = 1.0f / numsteps;
2754 VectorScale(stepdelta, w, stepdelta);
2755 VectorMA(clipstart, 0.5f, stepdelta, steppos);
2756 for (step = 0;step < numsteps;step++)
2758 r_refdef.stats.bouncegrid_splats++;
2759 // figure out which texture pixel this is in
2760 texlerp[1][0] = ((steppos[0] - mins[0]) * ispacing[0]) - 0.5f;
2761 texlerp[1][1] = ((steppos[1] - mins[1]) * ispacing[1]) - 0.5f;
2762 texlerp[1][2] = ((steppos[2] - mins[2]) * ispacing[2]) - 0.5f;
2763 tex[0] = (int)floor(texlerp[1][0]);
2764 tex[1] = (int)floor(texlerp[1][1]);
2765 tex[2] = (int)floor(texlerp[1][2]);
2766 if (tex[0] >= 1 && tex[1] >= 1 && tex[2] >= 1 && tex[0] < resolution[0] - 2 && tex[1] < resolution[1] - 2 && tex[2] < resolution[2] - 2)
2768 // it is within bounds... do the real work now
2769 // calculate the lerp factors
2770 texlerp[1][0] -= tex[0];
2771 texlerp[1][1] -= tex[1];
2772 texlerp[1][2] -= tex[2];
2773 texlerp[0][0] = 1.0f - texlerp[1][0];
2774 texlerp[0][1] = 1.0f - texlerp[1][1];
2775 texlerp[0][2] = 1.0f - texlerp[1][2];
2776 // calculate individual pixel indexes and weights
2777 pixelindex[0] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[0] = (texlerp[0][0]*texlerp[0][1]*texlerp[0][2]);
2778 pixelindex[1] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0]+1);pixelweight[1] = (texlerp[1][0]*texlerp[0][1]*texlerp[0][2]);
2779 pixelindex[2] = (((tex[2] )*resolution[1]+tex[1]+1)*resolution[0]+tex[0] );pixelweight[2] = (texlerp[0][0]*texlerp[1][1]*texlerp[0][2]);
2780 pixelindex[3] = (((tex[2] )*resolution[1]+tex[1]+1)*resolution[0]+tex[0]+1);pixelweight[3] = (texlerp[1][0]*texlerp[1][1]*texlerp[0][2]);
2781 pixelindex[4] = (((tex[2]+1)*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[4] = (texlerp[0][0]*texlerp[0][1]*texlerp[1][2]);
2782 pixelindex[5] = (((tex[2]+1)*resolution[1]+tex[1] )*resolution[0]+tex[0]+1);pixelweight[5] = (texlerp[1][0]*texlerp[0][1]*texlerp[1][2]);
2783 pixelindex[6] = (((tex[2]+1)*resolution[1]+tex[1]+1)*resolution[0]+tex[0] );pixelweight[6] = (texlerp[0][0]*texlerp[1][1]*texlerp[1][2]);
2784 pixelindex[7] = (((tex[2]+1)*resolution[1]+tex[1]+1)*resolution[0]+tex[0]+1);pixelweight[7] = (texlerp[1][0]*texlerp[1][1]*texlerp[1][2]);
2785 // update the 8 pixels...
2786 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2788 for (corner = 0;corner < 8;corner++)
2790 // calculate address for pixel
2791 w = pixelweight[corner];
2792 pixel = pixels + 4 * pixelindex[corner] + pixelband * pixelsperband * 4;
2793 highpixel = highpixels + 4 * pixelindex[corner] + pixelband * pixelsperband * 4;
2794 // add to the high precision pixel color
2795 highpixel[0] += (splatcolor[pixelband*4+0]*w);
2796 highpixel[1] += (splatcolor[pixelband*4+1]*w);
2797 highpixel[2] += (splatcolor[pixelband*4+2]*w);
2798 highpixel[3] += (splatcolor[pixelband*4+3]*w);
2799 // flag the low precision pixel as needing to be updated
2801 // advance to next band of coefficients
2802 //pixel += pixelsperband*4;
2803 //highpixel += pixelsperband*4;
2807 VectorAdd(steppos, stepdelta, steppos);
2810 if (cliptrace.fraction >= 1.0f)
2812 r_refdef.stats.bouncegrid_hits++;
2813 if (bouncecount >= maxbounce)
2815 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2816 // also clamp the resulting color to never add energy, even if the user requests extreme values
2817 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2818 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
2820 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
2821 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
2822 surfcolor[0] = min(surfcolor[0], 1.0f);
2823 surfcolor[1] = min(surfcolor[1], 1.0f);
2824 surfcolor[2] = min(surfcolor[2], 1.0f);
2825 VectorMultiply(shotcolor, surfcolor, shotcolor);
2826 if (VectorLength2(baseshotcolor) == 0.0f)
2828 r_refdef.stats.bouncegrid_bounces++;
2829 if (settings.bounceanglediffuse)
2831 // random direction, primarily along plane normal
2832 s = VectorDistance(cliptrace.endpos, clipend);
2833 if (settings.stablerandom < 0)
2834 VectorRandom(clipend);
2836 VectorCheeseRandom(clipend);
2837 VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
2838 VectorNormalize(clipend);
2839 VectorScale(clipend, s, clipend);
2843 // reflect the remaining portion of the line across plane normal
2844 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2845 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2847 // calculate the new line start and end
2848 VectorCopy(cliptrace.endpos, clipstart);
2849 VectorAdd(clipstart, clipend, clipend);
2853 // generate pixels array from highpixels array
2854 // skip first and last columns, rows, and layers as these are blank
2855 // the pixel[3] value was written above, so we can use it to detect only pixels that need to be calculated
2856 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2858 for (z = 1;z < resolution[2]-1;z++)
2860 for (y = 1;y < resolution[1]-1;y++)
2862 for (x = 1, pixelindex[0] = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x, pixel = pixels + 4*pixelindex[0], highpixel = highpixels + 4*pixelindex[0];x < resolution[0]-1;x++, pixel += 4, highpixel += 4)
2864 // only convert pixels that were hit by photons
2865 if (pixel[3] == 255)
2867 // normalize the bentnormal...
2870 VectorNormalize(highpixel);
2871 c[0] = (int)(highpixel[0]*128.0f+128.0f);
2872 c[1] = (int)(highpixel[1]*128.0f+128.0f);
2873 c[2] = (int)(highpixel[2]*128.0f+128.0f);
2874 c[3] = (int)(highpixel[3]*128.0f+128.0f);
2878 c[0] = (int)(highpixel[0]*256.0f);
2879 c[1] = (int)(highpixel[1]*256.0f);
2880 c[2] = (int)(highpixel[2]*256.0f);
2881 c[3] = (int)(highpixel[3]*256.0f);
2883 pixel[2] = (unsigned char)bound(0, c[0], 255);
2884 pixel[1] = (unsigned char)bound(0, c[1], 255);
2885 pixel[0] = (unsigned char)bound(0, c[2], 255);
2886 pixel[3] = (unsigned char)bound(0, c[3], 255);
2892 if (r_shadow_bouncegridtexture && r_shadow_bouncegridresolution[0] == resolution[0] && r_shadow_bouncegridresolution[1] == resolution[1] && r_shadow_bouncegridresolution[2] == resolution[2] && r_shadow_bouncegriddirectional == settings.directionalshading)
2893 R_UpdateTexture(r_shadow_bouncegridtexture, pixels, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2896 VectorCopy(resolution, r_shadow_bouncegridresolution);
2897 r_shadow_bouncegriddirectional = settings.directionalshading;
2898 if (r_shadow_bouncegridtexture)
2899 R_FreeTexture(r_shadow_bouncegridtexture);
2900 r_shadow_bouncegridtexture = R_LoadTexture3D(r_shadow_texturepool, "bouncegrid", resolution[0], resolution[1], resolution[2]*pixelbands, pixels, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, 0, NULL);
2902 r_shadow_bouncegridtime = realtime;
2905 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2907 R_Shadow_RenderMode_Reset();
2908 GL_BlendFunc(GL_ONE, GL_ONE);
2909 GL_DepthRange(0, 1);
2910 GL_DepthTest(r_showshadowvolumes.integer < 2);
2911 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2912 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2913 GL_CullFace(GL_NONE);
2914 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2917 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2919 R_Shadow_RenderMode_Reset();
2920 GL_BlendFunc(GL_ONE, GL_ONE);
2921 GL_DepthRange(0, 1);
2922 GL_DepthTest(r_showlighting.integer < 2);
2923 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2925 GL_DepthFunc(GL_EQUAL);
2926 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2927 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2930 void R_Shadow_RenderMode_End(void)
2932 R_Shadow_RenderMode_Reset();
2933 R_Shadow_RenderMode_ActiveLight(NULL);
2935 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2936 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2939 int bboxedges[12][2] =
2958 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2960 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
2962 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2963 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2964 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2965 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2968 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2969 return true; // invisible
2970 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2971 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2972 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2973 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2974 r_refdef.stats.lights_scissored++;
2978 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2981 const float *vertex3f;
2982 const float *normal3f;
2984 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2985 switch (r_shadow_rendermode)
2987 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2988 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2989 if (VectorLength2(diffusecolor) > 0)
2991 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)
2993 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2994 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2995 if ((dot = DotProduct(n, v)) < 0)
2997 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2998 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
3001 VectorCopy(ambientcolor, color4f);
3002 if (r_refdef.fogenabled)
3005 f = RSurf_FogVertex(vertex3f);
3006 VectorScale(color4f, f, color4f);
3013 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3015 VectorCopy(ambientcolor, color4f);
3016 if (r_refdef.fogenabled)
3019 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3020 f = RSurf_FogVertex(vertex3f);
3021 VectorScale(color4f + 4*i, f, color4f);
3027 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3028 if (VectorLength2(diffusecolor) > 0)
3030 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)
3032 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3033 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3035 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3036 if ((dot = DotProduct(n, v)) < 0)
3038 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3039 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3040 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3041 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3045 color4f[0] = ambientcolor[0] * distintensity;
3046 color4f[1] = ambientcolor[1] * distintensity;
3047 color4f[2] = ambientcolor[2] * distintensity;
3049 if (r_refdef.fogenabled)
3052 f = RSurf_FogVertex(vertex3f);
3053 VectorScale(color4f, f, color4f);
3057 VectorClear(color4f);
3063 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3065 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3066 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3068 color4f[0] = ambientcolor[0] * distintensity;
3069 color4f[1] = ambientcolor[1] * distintensity;
3070 color4f[2] = ambientcolor[2] * distintensity;
3071 if (r_refdef.fogenabled)
3074 f = RSurf_FogVertex(vertex3f);
3075 VectorScale(color4f, f, color4f);
3079 VectorClear(color4f);
3084 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3085 if (VectorLength2(diffusecolor) > 0)
3087 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)
3089 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3090 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3092 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3093 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3094 if ((dot = DotProduct(n, v)) < 0)
3096 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3097 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3098 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3099 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3103 color4f[0] = ambientcolor[0] * distintensity;
3104 color4f[1] = ambientcolor[1] * distintensity;
3105 color4f[2] = ambientcolor[2] * distintensity;
3107 if (r_refdef.fogenabled)
3110 f = RSurf_FogVertex(vertex3f);
3111 VectorScale(color4f, f, color4f);
3115 VectorClear(color4f);
3121 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3123 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3124 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3126 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3127 color4f[0] = ambientcolor[0] * distintensity;
3128 color4f[1] = ambientcolor[1] * distintensity;
3129 color4f[2] = ambientcolor[2] * distintensity;
3130 if (r_refdef.fogenabled)
3133 f = RSurf_FogVertex(vertex3f);
3134 VectorScale(color4f, f, color4f);
3138 VectorClear(color4f);
3148 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3150 // used to display how many times a surface is lit for level design purposes
3151 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3152 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3156 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
3158 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3159 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
3163 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3170 int newnumtriangles;
3174 int maxtriangles = 1024;
3175 int newelements[1024*3];
3176 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3177 for (renders = 0;renders < 4;renders++)
3182 newnumtriangles = 0;
3184 // due to low fillrate on the cards this vertex lighting path is
3185 // designed for, we manually cull all triangles that do not
3186 // contain a lit vertex
3187 // this builds batches of triangles from multiple surfaces and
3188 // renders them at once
3189 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3191 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3193 if (newnumtriangles)
3195 newfirstvertex = min(newfirstvertex, e[0]);
3196 newlastvertex = max(newlastvertex, e[0]);
3200 newfirstvertex = e[0];
3201 newlastvertex = e[0];
3203 newfirstvertex = min(newfirstvertex, e[1]);
3204 newlastvertex = max(newlastvertex, e[1]);
3205 newfirstvertex = min(newfirstvertex, e[2]);
3206 newlastvertex = max(newlastvertex, e[2]);
3212 if (newnumtriangles >= maxtriangles)
3214 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3215 newnumtriangles = 0;
3221 if (newnumtriangles >= 1)
3223 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3226 // if we couldn't find any lit triangles, exit early
3229 // now reduce the intensity for the next overbright pass
3230 // we have to clamp to 0 here incase the drivers have improper
3231 // handling of negative colors
3232 // (some old drivers even have improper handling of >1 color)
3234 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3236 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3238 c[0] = max(0, c[0] - 1);
3239 c[1] = max(0, c[1] - 1);
3240 c[2] = max(0, c[2] - 1);
3252 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
3254 // OpenGL 1.1 path (anything)
3255 float ambientcolorbase[3], diffusecolorbase[3];
3256 float ambientcolorpants[3], diffusecolorpants[3];
3257 float ambientcolorshirt[3], diffusecolorshirt[3];
3258 const float *surfacecolor = rsurface.texture->dlightcolor;
3259 const float *surfacepants = rsurface.colormap_pantscolor;
3260 const float *surfaceshirt = rsurface.colormap_shirtcolor;
3261 rtexture_t *basetexture = rsurface.texture->basetexture;
3262 rtexture_t *pantstexture = rsurface.texture->pantstexture;
3263 rtexture_t *shirttexture = rsurface.texture->shirttexture;
3264 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3265 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3266 ambientscale *= 2 * r_refdef.view.colorscale;
3267 diffusescale *= 2 * r_refdef.view.colorscale;
3268 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3269 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3270 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3271 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3272 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3273 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
3274 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3275 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
3276 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3277 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
3278 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
3279 R_Mesh_TexBind(0, basetexture);
3280 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
3281 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
3282 switch(r_shadow_rendermode)
3284 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3285 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
3286 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3287 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3288 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3290 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3291 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
3292 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
3293 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
3294 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3296 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3297 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
3298 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3299 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3300 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3302 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3307 //R_Mesh_TexBind(0, basetexture);
3308 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
3311 R_Mesh_TexBind(0, pantstexture);
3312 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
3316 R_Mesh_TexBind(0, shirttexture);
3317 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
3321 extern cvar_t gl_lightmaps;
3322 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3324 float ambientscale, diffusescale, specularscale;
3326 float lightcolor[3];
3327 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
3328 ambientscale = rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient;
3329 diffusescale = rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient);
3330 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3331 if (!r_shadow_usenormalmap.integer)
3333 ambientscale += 1.0f * diffusescale;
3337 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
3339 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
3342 VectorNegate(lightcolor, lightcolor);
3343 GL_BlendEquationSubtract(true);
3345 RSurf_SetupDepthAndCulling();
3346 switch (r_shadow_rendermode)
3348 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3349 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3350 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
3352 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3353 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
3355 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3356 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3357 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3358 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3359 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
3362 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3366 GL_BlendEquationSubtract(false);
3369 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)
3371 matrix4x4_t tempmatrix = *matrix;
3372 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3374 // if this light has been compiled before, free the associated data
3375 R_RTLight_Uncompile(rtlight);
3377 // clear it completely to avoid any lingering data
3378 memset(rtlight, 0, sizeof(*rtlight));
3380 // copy the properties
3381 rtlight->matrix_lighttoworld = tempmatrix;
3382 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3383 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3384 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3385 VectorCopy(color, rtlight->color);
3386 rtlight->cubemapname[0] = 0;
3387 if (cubemapname && cubemapname[0])
3388 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3389 rtlight->shadow = shadow;
3390 rtlight->corona = corona;
3391 rtlight->style = style;
3392 rtlight->isstatic = isstatic;
3393 rtlight->coronasizescale = coronasizescale;
3394 rtlight->ambientscale = ambientscale;
3395 rtlight->diffusescale = diffusescale;
3396 rtlight->specularscale = specularscale;
3397 rtlight->flags = flags;
3399 // compute derived data
3400 //rtlight->cullradius = rtlight->radius;
3401 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3402 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3403 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3404 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3405 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3406 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3407 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3410 // compiles rtlight geometry
3411 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3412 void R_RTLight_Compile(rtlight_t *rtlight)
3415 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3416 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3417 entity_render_t *ent = r_refdef.scene.worldentity;
3418 dp_model_t *model = r_refdef.scene.worldmodel;
3419 unsigned char *data;
3422 // compile the light
3423 rtlight->compiled = true;
3424 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3425 rtlight->static_numleafs = 0;
3426 rtlight->static_numleafpvsbytes = 0;
3427 rtlight->static_leaflist = NULL;
3428 rtlight->static_leafpvs = NULL;
3429 rtlight->static_numsurfaces = 0;
3430 rtlight->static_surfacelist = NULL;
3431 rtlight->static_shadowmap_receivers = 0x3F;
3432 rtlight->static_shadowmap_casters = 0x3F;
3433 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3434 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3435 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3436 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3437 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3438 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3440 if (model && model->GetLightInfo)
3442 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3443 r_shadow_compilingrtlight = rtlight;
3444 R_FrameData_SetMark();
3445 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);
3446 R_FrameData_ReturnToMark();
3447 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3448 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3449 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3450 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3451 rtlight->static_numsurfaces = numsurfaces;
3452 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3453 rtlight->static_numleafs = numleafs;
3454 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3455 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3456 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3457 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3458 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3459 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3460 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3461 if (rtlight->static_numsurfaces)
3462 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3463 if (rtlight->static_numleafs)
3464 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3465 if (rtlight->static_numleafpvsbytes)
3466 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3467 if (rtlight->static_numshadowtrispvsbytes)
3468 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3469 if (rtlight->static_numlighttrispvsbytes)
3470 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3471 R_FrameData_SetMark();
3472 switch (rtlight->shadowmode)
3474 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3475 if (model->CompileShadowMap && rtlight->shadow)
3476 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3479 if (model->CompileShadowVolume && rtlight->shadow)
3480 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3483 R_FrameData_ReturnToMark();
3484 // now we're done compiling the rtlight
3485 r_shadow_compilingrtlight = NULL;
3489 // use smallest available cullradius - box radius or light radius
3490 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3491 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3493 shadowzpasstris = 0;
3494 if (rtlight->static_meshchain_shadow_zpass)
3495 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3496 shadowzpasstris += mesh->numtriangles;
3498 shadowzfailtris = 0;
3499 if (rtlight->static_meshchain_shadow_zfail)
3500 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3501 shadowzfailtris += mesh->numtriangles;
3504 if (rtlight->static_numlighttrispvsbytes)
3505 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3506 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3510 if (rtlight->static_numlighttrispvsbytes)
3511 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3512 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3515 if (developer_extra.integer)
3516 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);
3519 void R_RTLight_Uncompile(rtlight_t *rtlight)
3521 if (rtlight->compiled)
3523 if (rtlight->static_meshchain_shadow_zpass)
3524 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3525 rtlight->static_meshchain_shadow_zpass = NULL;
3526 if (rtlight->static_meshchain_shadow_zfail)
3527 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3528 rtlight->static_meshchain_shadow_zfail = NULL;
3529 if (rtlight->static_meshchain_shadow_shadowmap)
3530 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3531 rtlight->static_meshchain_shadow_shadowmap = NULL;
3532 // these allocations are grouped
3533 if (rtlight->static_surfacelist)
3534 Mem_Free(rtlight->static_surfacelist);
3535 rtlight->static_numleafs = 0;
3536 rtlight->static_numleafpvsbytes = 0;
3537 rtlight->static_leaflist = NULL;
3538 rtlight->static_leafpvs = NULL;
3539 rtlight->static_numsurfaces = 0;
3540 rtlight->static_surfacelist = NULL;
3541 rtlight->static_numshadowtrispvsbytes = 0;
3542 rtlight->static_shadowtrispvs = NULL;
3543 rtlight->static_numlighttrispvsbytes = 0;
3544 rtlight->static_lighttrispvs = NULL;
3545 rtlight->compiled = false;
3549 void R_Shadow_UncompileWorldLights(void)
3553 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3554 for (lightindex = 0;lightindex < range;lightindex++)
3556 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3559 R_RTLight_Uncompile(&light->rtlight);
3563 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3567 // reset the count of frustum planes
3568 // see rtlight->cached_frustumplanes definition for how much this array
3570 rtlight->cached_numfrustumplanes = 0;
3572 if (r_trippy.integer)
3575 // haven't implemented a culling path for ortho rendering
3576 if (!r_refdef.view.useperspective)
3578 // check if the light is on screen and copy the 4 planes if it is
3579 for (i = 0;i < 4;i++)
3580 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3583 for (i = 0;i < 4;i++)
3584 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3589 // generate a deformed frustum that includes the light origin, this is
3590 // used to cull shadow casting surfaces that can not possibly cast a
3591 // shadow onto the visible light-receiving surfaces, which can be a
3594 // if the light origin is onscreen the result will be 4 planes exactly
3595 // if the light origin is offscreen on only one axis the result will
3596 // be exactly 5 planes (split-side case)
3597 // if the light origin is offscreen on two axes the result will be
3598 // exactly 4 planes (stretched corner case)
3599 for (i = 0;i < 4;i++)
3601 // quickly reject standard frustum planes that put the light
3602 // origin outside the frustum
3603 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3606 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3608 // if all the standard frustum planes were accepted, the light is onscreen
3609 // otherwise we need to generate some more planes below...
3610 if (rtlight->cached_numfrustumplanes < 4)
3612 // at least one of the stock frustum planes failed, so we need to
3613 // create one or two custom planes to enclose the light origin
3614 for (i = 0;i < 4;i++)
3616 // create a plane using the view origin and light origin, and a
3617 // single point from the frustum corner set
3618 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3619 VectorNormalize(plane.normal);
3620 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3621 // see if this plane is backwards and flip it if so
3622 for (j = 0;j < 4;j++)
3623 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3627 VectorNegate(plane.normal, plane.normal);
3629 // flipped plane, test again to see if it is now valid
3630 for (j = 0;j < 4;j++)
3631 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3633 // if the plane is still not valid, then it is dividing the
3634 // frustum and has to be rejected
3638 // we have created a valid plane, compute extra info
3639 PlaneClassify(&plane);
3641 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3643 // if we've found 5 frustum planes then we have constructed a
3644 // proper split-side case and do not need to keep searching for
3645 // planes to enclose the light origin
3646 if (rtlight->cached_numfrustumplanes == 5)
3654 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3656 plane = rtlight->cached_frustumplanes[i];
3657 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));
3662 // now add the light-space box planes if the light box is rotated, as any
3663 // caster outside the oriented light box is irrelevant (even if it passed
3664 // the worldspace light box, which is axial)
3665 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3667 for (i = 0;i < 6;i++)
3671 v[i >> 1] = (i & 1) ? -1 : 1;
3672 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3673 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3674 plane.dist = VectorNormalizeLength(plane.normal);
3675 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3676 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3682 // add the world-space reduced box planes
3683 for (i = 0;i < 6;i++)
3685 VectorClear(plane.normal);
3686 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3687 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3688 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3697 // reduce all plane distances to tightly fit the rtlight cull box, which
3699 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3700 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3701 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3702 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3703 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3704 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3705 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3706 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3707 oldnum = rtlight->cached_numfrustumplanes;
3708 rtlight->cached_numfrustumplanes = 0;
3709 for (j = 0;j < oldnum;j++)
3711 // find the nearest point on the box to this plane
3712 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3713 for (i = 1;i < 8;i++)
3715 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3716 if (bestdist > dist)
3719 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);
3720 // if the nearest point is near or behind the plane, we want this
3721 // plane, otherwise the plane is useless as it won't cull anything
3722 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3724 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3725 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3732 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3736 RSurf_ActiveWorldEntity();
3738 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3741 GL_CullFace(GL_NONE);
3742 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3743 for (;mesh;mesh = mesh->next)
3745 if (!mesh->sidetotals[r_shadow_shadowmapside])
3747 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3748 if (mesh->vertex3fbuffer)
3749 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3751 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3752 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);
3756 else if (r_refdef.scene.worldentity->model)
3757 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);
3759 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3762 static void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3764 qboolean zpass = false;
3767 int surfacelistindex;
3768 msurface_t *surface;
3770 // if triangle neighbors are disabled, shadowvolumes are disabled
3771 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
3774 RSurf_ActiveWorldEntity();
3776 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3779 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3781 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3782 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3784 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3785 for (;mesh;mesh = mesh->next)
3787 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3788 if (mesh->vertex3fbuffer)
3789 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3791 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3792 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3794 // increment stencil if frontface is infront of depthbuffer
3795 GL_CullFace(r_refdef.view.cullface_back);
3796 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3797 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);
3798 // decrement stencil if backface is infront of depthbuffer
3799 GL_CullFace(r_refdef.view.cullface_front);
3800 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3802 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3804 // decrement stencil if backface is behind depthbuffer
3805 GL_CullFace(r_refdef.view.cullface_front);
3806 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3807 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);
3808 // increment stencil if frontface is behind depthbuffer
3809 GL_CullFace(r_refdef.view.cullface_back);
3810 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3812 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);
3816 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3818 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3819 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3820 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3822 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3823 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3824 if (CHECKPVSBIT(trispvs, t))
3825 shadowmarklist[numshadowmark++] = t;
3827 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);
3829 else if (numsurfaces)
3831 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);
3834 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3837 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3839 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3840 vec_t relativeshadowradius;
3841 RSurf_ActiveModelEntity(ent, false, false, false);
3842 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3843 // we need to re-init the shader for each entity because the matrix changed
3844 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3845 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3846 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3847 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3848 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3849 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3850 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3851 switch (r_shadow_rendermode)
3853 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3854 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3857 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3860 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3863 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3865 // set up properties for rendering light onto this entity
3866 RSurf_ActiveModelEntity(ent, true, true, false);
3867 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3868 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3869 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3870 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3873 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3875 if (!r_refdef.scene.worldmodel->DrawLight)
3878 // set up properties for rendering light onto this entity
3879 RSurf_ActiveWorldEntity();
3880 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3881 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3882 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3883 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3885 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3887 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3890 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
3892 dp_model_t *model = ent->model;
3893 if (!model->DrawLight)
3896 R_Shadow_SetupEntityLight(ent);
3898 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3900 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3903 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
3907 int numleafs, numsurfaces;
3908 int *leaflist, *surfacelist;
3909 unsigned char *leafpvs;
3910 unsigned char *shadowtrispvs;
3911 unsigned char *lighttrispvs;
3912 //unsigned char *surfacesides;
3913 int numlightentities;
3914 int numlightentities_noselfshadow;
3915 int numshadowentities;
3916 int numshadowentities_noselfshadow;
3917 static entity_render_t *lightentities[MAX_EDICTS];
3918 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3919 static entity_render_t *shadowentities[MAX_EDICTS];
3920 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3923 rtlight->draw = false;
3925 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3926 // skip lights that are basically invisible (color 0 0 0)
3927 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3929 // loading is done before visibility checks because loading should happen
3930 // all at once at the start of a level, not when it stalls gameplay.
3931 // (especially important to benchmarks)
3933 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3935 if (rtlight->compiled)
3936 R_RTLight_Uncompile(rtlight);
3937 R_RTLight_Compile(rtlight);
3941 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3943 // look up the light style value at this time
3944 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3945 VectorScale(rtlight->color, f, rtlight->currentcolor);
3947 if (rtlight->selected)
3949 f = 2 + sin(realtime * M_PI * 4.0);
3950 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3954 // if lightstyle is currently off, don't draw the light
3955 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3958 // skip processing on corona-only lights
3962 // if the light box is offscreen, skip it
3963 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3966 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3967 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3969 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3971 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3973 // compiled light, world available and can receive realtime lighting
3974 // retrieve leaf information
3975 numleafs = rtlight->static_numleafs;
3976 leaflist = rtlight->static_leaflist;
3977 leafpvs = rtlight->static_leafpvs;
3978 numsurfaces = rtlight->static_numsurfaces;
3979 surfacelist = rtlight->static_surfacelist;
3980 //surfacesides = NULL;
3981 shadowtrispvs = rtlight->static_shadowtrispvs;
3982 lighttrispvs = rtlight->static_lighttrispvs;
3984 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3986 // dynamic light, world available and can receive realtime lighting
3987 // calculate lit surfaces and leafs
3988 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);
3989 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3990 leaflist = r_shadow_buffer_leaflist;
3991 leafpvs = r_shadow_buffer_leafpvs;
3992 surfacelist = r_shadow_buffer_surfacelist;
3993 //surfacesides = r_shadow_buffer_surfacesides;
3994 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3995 lighttrispvs = r_shadow_buffer_lighttrispvs;
3996 // if the reduced leaf bounds are offscreen, skip it
3997 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4008 //surfacesides = NULL;
4009 shadowtrispvs = NULL;
4010 lighttrispvs = NULL;
4012 // check if light is illuminating any visible leafs
4015 for (i = 0;i < numleafs;i++)
4016 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4022 // make a list of lit entities and shadow casting entities
4023 numlightentities = 0;
4024 numlightentities_noselfshadow = 0;
4025 numshadowentities = 0;
4026 numshadowentities_noselfshadow = 0;
4028 // add dynamic entities that are lit by the light
4029 for (i = 0;i < r_refdef.scene.numentities;i++)
4032 entity_render_t *ent = r_refdef.scene.entities[i];
4034 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4036 // skip the object entirely if it is not within the valid
4037 // shadow-casting region (which includes the lit region)
4038 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
4040 if (!(model = ent->model))
4042 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4044 // this entity wants to receive light, is visible, and is
4045 // inside the light box
4046 // TODO: check if the surfaces in the model can receive light
4047 // so now check if it's in a leaf seen by the light
4048 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))
4050 if (ent->flags & RENDER_NOSELFSHADOW)
4051 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
4053 lightentities[numlightentities++] = ent;
4054 // since it is lit, it probably also casts a shadow...
4055 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4056 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4057 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4059 // note: exterior models without the RENDER_NOSELFSHADOW
4060 // flag still create a RENDER_NOSELFSHADOW shadow but
4061 // are lit normally, this means that they are
4062 // self-shadowing but do not shadow other
4063 // RENDER_NOSELFSHADOW entities such as the gun
4064 // (very weird, but keeps the player shadow off the gun)
4065 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4066 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4068 shadowentities[numshadowentities++] = ent;
4071 else if (ent->flags & RENDER_SHADOW)
4073 // this entity is not receiving light, but may still need to
4075 // TODO: check if the surfaces in the model can cast shadow
4076 // now check if it is in a leaf seen by the light
4077 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))
4079 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4080 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4081 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4083 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4084 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4086 shadowentities[numshadowentities++] = ent;
4091 // return if there's nothing at all to light
4092 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4095 // count this light in the r_speeds
4096 r_refdef.stats.lights++;
4098 // flag it as worth drawing later
4099 rtlight->draw = true;
4101 // cache all the animated entities that cast a shadow but are not visible
4102 for (i = 0;i < numshadowentities;i++)
4103 if (!shadowentities[i]->animcache_vertex3f)
4104 R_AnimCache_GetEntity(shadowentities[i], false, false);
4105 for (i = 0;i < numshadowentities_noselfshadow;i++)
4106 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
4107 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4109 // allocate some temporary memory for rendering this light later in the frame
4110 // reusable buffers need to be copied, static data can be used as-is
4111 rtlight->cached_numlightentities = numlightentities;
4112 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
4113 rtlight->cached_numshadowentities = numshadowentities;
4114 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4115 rtlight->cached_numsurfaces = numsurfaces;
4116 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4117 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4118 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4119 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4120 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4122 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4123 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4124 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4125 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4126 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4130 // compiled light data
4131 rtlight->cached_shadowtrispvs = shadowtrispvs;
4132 rtlight->cached_lighttrispvs = lighttrispvs;
4133 rtlight->cached_surfacelist = surfacelist;
4137 static void R_Shadow_DrawLight(rtlight_t *rtlight)
4141 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4142 int numlightentities;
4143 int numlightentities_noselfshadow;
4144 int numshadowentities;
4145 int numshadowentities_noselfshadow;
4146 entity_render_t **lightentities;
4147 entity_render_t **lightentities_noselfshadow;
4148 entity_render_t **shadowentities;
4149 entity_render_t **shadowentities_noselfshadow;
4151 static unsigned char entitysides[MAX_EDICTS];
4152 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4153 vec3_t nearestpoint;
4155 qboolean castshadows;
4158 // check if we cached this light this frame (meaning it is worth drawing)
4162 numlightentities = rtlight->cached_numlightentities;
4163 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4164 numshadowentities = rtlight->cached_numshadowentities;
4165 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4166 numsurfaces = rtlight->cached_numsurfaces;
4167 lightentities = rtlight->cached_lightentities;
4168 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4169 shadowentities = rtlight->cached_shadowentities;
4170 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4171 shadowtrispvs = rtlight->cached_shadowtrispvs;
4172 lighttrispvs = rtlight->cached_lighttrispvs;
4173 surfacelist = rtlight->cached_surfacelist;
4175 // set up a scissor rectangle for this light
4176 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4179 // don't let sound skip if going slow
4180 if (r_refdef.scene.extraupdate)
4183 // make this the active rtlight for rendering purposes
4184 R_Shadow_RenderMode_ActiveLight(rtlight);
4186 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4188 // optionally draw visible shape of the shadow volumes
4189 // for performance analysis by level designers
4190 R_Shadow_RenderMode_VisibleShadowVolumes();
4192 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4193 for (i = 0;i < numshadowentities;i++)
4194 R_Shadow_DrawEntityShadow(shadowentities[i]);
4195 for (i = 0;i < numshadowentities_noselfshadow;i++)
4196 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4197 R_Shadow_RenderMode_VisibleLighting(false, false);
4200 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4202 // optionally draw the illuminated areas
4203 // for performance analysis by level designers
4204 R_Shadow_RenderMode_VisibleLighting(false, false);
4206 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4207 for (i = 0;i < numlightentities;i++)
4208 R_Shadow_DrawEntityLight(lightentities[i]);
4209 for (i = 0;i < numlightentities_noselfshadow;i++)
4210 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4213 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4215 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4216 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4217 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4218 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4220 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
4221 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4222 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4224 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4230 int receivermask = 0;
4231 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4232 Matrix4x4_Abs(&radiustolight);
4234 r_shadow_shadowmaplod = 0;
4235 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4236 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
4237 r_shadow_shadowmaplod = i;
4239 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4241 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4243 surfacesides = NULL;
4246 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4248 castermask = rtlight->static_shadowmap_casters;
4249 receivermask = rtlight->static_shadowmap_receivers;
4253 surfacesides = r_shadow_buffer_surfacesides;
4254 for(i = 0;i < numsurfaces;i++)
4256 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4257 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4258 castermask |= surfacesides[i];
4259 receivermask |= surfacesides[i];
4263 if (receivermask < 0x3F)
4265 for (i = 0;i < numlightentities;i++)
4266 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4267 if (receivermask < 0x3F)
4268 for(i = 0; i < numlightentities_noselfshadow;i++)
4269 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4272 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4276 for (i = 0;i < numshadowentities;i++)
4277 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4278 for (i = 0;i < numshadowentities_noselfshadow;i++)
4279 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4282 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4284 // render shadow casters into 6 sided depth texture
4285 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4287 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
4288 if (! (castermask & (1 << side))) continue;
4290 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4291 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4292 R_Shadow_DrawEntityShadow(shadowentities[i]);
4295 if (numlightentities_noselfshadow)
4297 // render lighting using the depth texture as shadowmap
4298 // draw lighting in the unmasked areas
4299 R_Shadow_RenderMode_Lighting(false, false, true);
4300 for (i = 0;i < numlightentities_noselfshadow;i++)
4301 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4304 // render shadow casters into 6 sided depth texture
4305 if (numshadowentities_noselfshadow)
4307 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4309 R_Shadow_RenderMode_ShadowMap(side, 0, size);
4310 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
4311 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4315 // render lighting using the depth texture as shadowmap
4316 // draw lighting in the unmasked areas
4317 R_Shadow_RenderMode_Lighting(false, false, true);
4318 // draw lighting in the unmasked areas
4320 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4321 for (i = 0;i < numlightentities;i++)
4322 R_Shadow_DrawEntityLight(lightentities[i]);
4324 else if (castshadows && vid.stencil)
4326 // draw stencil shadow volumes to mask off pixels that are in shadow
4327 // so that they won't receive lighting
4328 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4329 R_Shadow_ClearStencil();
4332 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4333 for (i = 0;i < numshadowentities;i++)
4334 R_Shadow_DrawEntityShadow(shadowentities[i]);
4336 // draw lighting in the unmasked areas
4337 R_Shadow_RenderMode_Lighting(true, false, false);
4338 for (i = 0;i < numlightentities_noselfshadow;i++)
4339 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4341 for (i = 0;i < numshadowentities_noselfshadow;i++)
4342 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4344 // draw lighting in the unmasked areas
4345 R_Shadow_RenderMode_Lighting(true, false, false);
4347 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4348 for (i = 0;i < numlightentities;i++)
4349 R_Shadow_DrawEntityLight(lightentities[i]);
4353 // draw lighting in the unmasked areas
4354 R_Shadow_RenderMode_Lighting(false, false, false);
4356 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4357 for (i = 0;i < numlightentities;i++)
4358 R_Shadow_DrawEntityLight(lightentities[i]);
4359 for (i = 0;i < numlightentities_noselfshadow;i++)
4360 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4363 if (r_shadow_usingdeferredprepass)
4365 // when rendering deferred lighting, we simply rasterize the box
4366 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4367 R_Shadow_RenderMode_DrawDeferredLight(false, true);
4368 else if (castshadows && vid.stencil)
4369 R_Shadow_RenderMode_DrawDeferredLight(true, false);
4371 R_Shadow_RenderMode_DrawDeferredLight(false, false);
4375 static void R_Shadow_FreeDeferred(void)
4377 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
4378 r_shadow_prepassgeometryfbo = 0;
4380 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
4381 r_shadow_prepasslightingdiffusespecularfbo = 0;
4383 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
4384 r_shadow_prepasslightingdiffusefbo = 0;
4386 if (r_shadow_prepassgeometrydepthbuffer)
4387 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
4388 r_shadow_prepassgeometrydepthbuffer = NULL;
4390 if (r_shadow_prepassgeometrynormalmaptexture)
4391 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4392 r_shadow_prepassgeometrynormalmaptexture = NULL;
4394 if (r_shadow_prepasslightingdiffusetexture)
4395 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
4396 r_shadow_prepasslightingdiffusetexture = NULL;
4398 if (r_shadow_prepasslightingspeculartexture)
4399 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4400 r_shadow_prepasslightingspeculartexture = NULL;
4403 void R_Shadow_DrawPrepass(void)
4411 entity_render_t *ent;
4412 float clearcolor[4];
4414 R_Mesh_ResetTextureState();
4416 GL_ColorMask(1,1,1,1);
4417 GL_BlendFunc(GL_ONE, GL_ZERO);
4420 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4421 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4422 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4423 if (r_timereport_active)
4424 R_TimeReport("prepasscleargeom");
4426 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4427 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4428 if (r_timereport_active)
4429 R_TimeReport("prepassworld");
4431 for (i = 0;i < r_refdef.scene.numentities;i++)
4433 if (!r_refdef.viewcache.entityvisible[i])
4435 ent = r_refdef.scene.entities[i];
4436 if (ent->model && ent->model->DrawPrepass != NULL)
4437 ent->model->DrawPrepass(ent);
4440 if (r_timereport_active)
4441 R_TimeReport("prepassmodels");
4443 GL_DepthMask(false);
4444 GL_ColorMask(1,1,1,1);
4447 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4448 Vector4Set(clearcolor, 0, 0, 0, 0);
4449 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4450 if (r_timereport_active)
4451 R_TimeReport("prepassclearlit");
4453 R_Shadow_RenderMode_Begin();
4455 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4456 if (r_shadow_debuglight.integer >= 0)
4458 lightindex = r_shadow_debuglight.integer;
4459 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4460 if (light && (light->flags & flag) && light->rtlight.draw)
4461 R_Shadow_DrawLight(&light->rtlight);
4465 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4466 for (lightindex = 0;lightindex < range;lightindex++)
4468 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4469 if (light && (light->flags & flag) && light->rtlight.draw)
4470 R_Shadow_DrawLight(&light->rtlight);
4473 if (r_refdef.scene.rtdlight)
4474 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4475 if (r_refdef.scene.lights[lnum]->draw)
4476 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4478 R_Shadow_RenderMode_End();
4480 if (r_timereport_active)
4481 R_TimeReport("prepasslights");
4484 void R_Shadow_DrawLightSprites(void);
4485 void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
4494 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4495 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4496 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
4497 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4498 r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) ||
4499 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4500 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4501 R_Shadow_FreeShadowMaps();
4503 r_shadow_fb_fbo = fbo;
4504 r_shadow_fb_depthtexture = depthtexture;
4505 r_shadow_fb_colortexture = colortexture;
4507 r_shadow_usingshadowmaportho = false;
4509 switch (vid.renderpath)
4511 case RENDERPATH_GL20:
4512 case RENDERPATH_D3D9:
4513 case RENDERPATH_D3D10:
4514 case RENDERPATH_D3D11:
4515 case RENDERPATH_SOFT:
4517 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4519 r_shadow_usingdeferredprepass = false;
4520 if (r_shadow_prepass_width)
4521 R_Shadow_FreeDeferred();
4522 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4526 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4528 R_Shadow_FreeDeferred();
4530 r_shadow_usingdeferredprepass = true;
4531 r_shadow_prepass_width = vid.width;
4532 r_shadow_prepass_height = vid.height;
4533 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
4534 r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER16F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4535 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);
4536 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);
4538 // set up the geometry pass fbo (depth + normalmap)
4539 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4540 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4541 // render depth into a renderbuffer and other important properties into the normalmap texture
4543 // set up the lighting pass fbo (diffuse + specular)
4544 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4545 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4546 // render diffuse into one texture and specular into another,
4547 // with depth and normalmap bound as textures,
4548 // with depth bound as attachment as well
4550 // set up the lighting pass fbo (diffuse)
4551 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4552 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4553 // render diffuse into one texture,
4554 // with depth and normalmap bound as textures,
4555 // with depth bound as attachment as well
4559 case RENDERPATH_GL11:
4560 case RENDERPATH_GL13:
4561 case RENDERPATH_GLES1:
4562 case RENDERPATH_GLES2:
4563 r_shadow_usingdeferredprepass = false;
4567 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);
4569 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4570 if (r_shadow_bouncegrid.integer != 2)
4572 if (r_shadow_debuglight.integer >= 0)
4574 lightindex = r_shadow_debuglight.integer;
4575 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4577 R_Shadow_PrepareLight(&light->rtlight);
4581 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4582 for (lightindex = 0;lightindex < range;lightindex++)
4584 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4585 if (light && (light->flags & flag))
4586 R_Shadow_PrepareLight(&light->rtlight);
4590 if (r_refdef.scene.rtdlight)
4592 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4593 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4595 else if(gl_flashblend.integer)
4597 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4599 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4600 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4601 VectorScale(rtlight->color, f, rtlight->currentcolor);
4605 if (r_editlights.integer)
4606 R_Shadow_DrawLightSprites();
4609 void R_Shadow_DrawLights(void)
4617 R_Shadow_RenderMode_Begin();
4619 if (r_shadow_bouncegrid.integer != 2)
4621 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4622 if (r_shadow_debuglight.integer >= 0)
4624 lightindex = r_shadow_debuglight.integer;
4625 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4627 R_Shadow_DrawLight(&light->rtlight);
4631 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4632 for (lightindex = 0;lightindex < range;lightindex++)
4634 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4635 if (light && (light->flags & flag))
4636 R_Shadow_DrawLight(&light->rtlight);
4640 if (r_refdef.scene.rtdlight)
4641 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4642 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4644 R_Shadow_RenderMode_End();
4647 void R_Shadow_PrepareModelShadows(void)
4650 float scale, size, radius, dot1, dot2;
4651 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4652 entity_render_t *ent;
4654 if (!r_refdef.scene.numentities)
4657 switch (r_shadow_shadowmode)
4659 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4660 if (r_shadows.integer >= 2)
4663 case R_SHADOW_SHADOWMODE_STENCIL:
4664 for (i = 0;i < r_refdef.scene.numentities;i++)
4666 ent = r_refdef.scene.entities[i];
4667 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4668 R_AnimCache_GetEntity(ent, false, false);
4675 size = 2*r_shadow_shadowmapmaxsize;
4676 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4677 radius = 0.5f * size / scale;
4679 Math_atov(r_shadows_throwdirection.string, shadowdir);
4680 VectorNormalize(shadowdir);
4681 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4682 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4683 if (fabs(dot1) <= fabs(dot2))
4684 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4686 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4687 VectorNormalize(shadowforward);
4688 CrossProduct(shadowdir, shadowforward, shadowright);
4689 Math_atov(r_shadows_focus.string, shadowfocus);
4690 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4691 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4692 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4693 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4694 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4696 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4698 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4699 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4700 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4701 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4702 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4703 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4705 for (i = 0;i < r_refdef.scene.numentities;i++)
4707 ent = r_refdef.scene.entities[i];
4708 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4710 // cast shadows from anything of the map (submodels are optional)
4711 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4712 R_AnimCache_GetEntity(ent, false, false);
4716 void R_DrawModelShadowMaps(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
4719 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4720 entity_render_t *ent;
4721 vec3_t relativelightorigin;
4722 vec3_t relativelightdirection, relativeforward, relativeright;
4723 vec3_t relativeshadowmins, relativeshadowmaxs;
4724 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4726 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4727 r_viewport_t viewport;
4728 GLuint shadowfbo = 0;
4729 float clearcolor[4];
4731 if (!r_refdef.scene.numentities)
4734 switch (r_shadow_shadowmode)
4736 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4742 r_shadow_fb_fbo = fbo;
4743 r_shadow_fb_depthtexture = depthtexture;
4744 r_shadow_fb_colortexture = colortexture;
4746 R_ResetViewRendering3D(fbo, depthtexture, colortexture);
4747 R_Shadow_RenderMode_Begin();
4748 R_Shadow_RenderMode_ActiveLight(NULL);
4750 switch (r_shadow_shadowmode)
4752 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4753 if (!r_shadow_shadowmap2ddepthtexture)
4754 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4755 shadowfbo = r_shadow_fbo2d;
4756 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
4757 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
4758 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4764 size = 2*r_shadow_shadowmapmaxsize;
4765 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4766 radius = 0.5f / scale;
4767 nearclip = -r_shadows_throwdistance.value;
4768 farclip = r_shadows_throwdistance.value;
4769 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4771 r_shadow_shadowmap_parameters[0] = size;
4772 r_shadow_shadowmap_parameters[1] = size;
4773 r_shadow_shadowmap_parameters[2] = 1.0;
4774 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4776 Math_atov(r_shadows_throwdirection.string, shadowdir);
4777 VectorNormalize(shadowdir);
4778 Math_atov(r_shadows_focus.string, shadowfocus);
4779 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4780 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4781 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4782 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4783 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4784 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4785 if (fabs(dot1) <= fabs(dot2))
4786 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4788 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4789 VectorNormalize(shadowforward);
4790 VectorM(scale, shadowforward, &m[0]);
4791 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4793 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4794 CrossProduct(shadowdir, shadowforward, shadowright);
4795 VectorM(scale, shadowright, &m[4]);
4796 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4797 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4798 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4799 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4800 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4801 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4803 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4805 if (r_shadow_shadowmap2ddepthbuffer)
4806 R_Mesh_SetRenderTargets(shadowfbo, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
4808 R_Mesh_SetRenderTargets(shadowfbo, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
4809 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL);
4810 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4813 R_SetViewport(&viewport);
4814 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4815 Vector4Set(clearcolor, 1,1,1,1);
4816 // in D3D9 we have to render to a color texture shadowmap
4817 // in GL we render directly to a depth texture only
4818 if (r_shadow_shadowmap2ddepthbuffer)
4819 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4821 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4822 // render into a slightly restricted region so that the borders of the
4823 // shadowmap area fade away, rather than streaking across everything
4824 // outside the usable area
4825 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4829 R_Mesh_SetRenderTargets(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture, NULL, NULL, NULL);
4830 R_SetupShader_ShowDepth(true);
4831 GL_ColorMask(1,1,1,1);
4832 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4835 for (i = 0;i < r_refdef.scene.numentities;i++)
4837 ent = r_refdef.scene.entities[i];
4839 // cast shadows from anything of the map (submodels are optional)
4840 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4842 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4843 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4844 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4845 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4846 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4847 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4848 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4849 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4850 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4851 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4852 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4853 RSurf_ActiveModelEntity(ent, false, false, false);
4854 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4855 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4862 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4864 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4866 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4867 Cvar_SetValueQuick(&r_test, 0);
4872 R_Shadow_RenderMode_End();
4874 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4875 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4876 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4877 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4878 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4879 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4881 switch (vid.renderpath)
4883 case RENDERPATH_GL11:
4884 case RENDERPATH_GL13:
4885 case RENDERPATH_GL20:
4886 case RENDERPATH_SOFT:
4887 case RENDERPATH_GLES1:
4888 case RENDERPATH_GLES2:
4890 case RENDERPATH_D3D9:
4891 case RENDERPATH_D3D10:
4892 case RENDERPATH_D3D11:
4893 #ifdef OPENGL_ORIENTATION
4894 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4895 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
4896 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
4897 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
4899 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4900 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
4901 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
4902 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
4907 r_shadow_usingshadowmaportho = true;
4908 switch (r_shadow_shadowmode)
4910 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4911 r_shadow_usingshadowmap2d = true;
4918 void R_DrawModelShadows(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
4921 float relativethrowdistance;
4922 entity_render_t *ent;
4923 vec3_t relativelightorigin;
4924 vec3_t relativelightdirection;
4925 vec3_t relativeshadowmins, relativeshadowmaxs;
4926 vec3_t tmp, shadowdir;
4928 if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4931 r_shadow_fb_fbo = fbo;
4932 r_shadow_fb_depthtexture = depthtexture;
4933 r_shadow_fb_colortexture = colortexture;
4935 R_ResetViewRendering3D(fbo, depthtexture, colortexture);
4936 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4937 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4938 R_Shadow_RenderMode_Begin();
4939 R_Shadow_RenderMode_ActiveLight(NULL);
4940 r_shadow_lightscissor[0] = r_refdef.view.x;
4941 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4942 r_shadow_lightscissor[2] = r_refdef.view.width;
4943 r_shadow_lightscissor[3] = r_refdef.view.height;
4944 R_Shadow_RenderMode_StencilShadowVolumes(false);
4947 if (r_shadows.integer == 2)
4949 Math_atov(r_shadows_throwdirection.string, shadowdir);
4950 VectorNormalize(shadowdir);
4953 R_Shadow_ClearStencil();
4955 for (i = 0;i < r_refdef.scene.numentities;i++)
4957 ent = r_refdef.scene.entities[i];
4959 // cast shadows from anything of the map (submodels are optional)
4960 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4962 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4963 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4964 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4965 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4966 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4969 if(ent->entitynumber != 0)
4971 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4973 // FIXME handle this
4974 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4978 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4979 int entnum, entnum2, recursion;
4980 entnum = entnum2 = ent->entitynumber;
4981 for(recursion = 32; recursion > 0; --recursion)
4983 entnum2 = cl.entities[entnum].state_current.tagentity;
4984 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4989 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4991 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4992 // transform into modelspace of OUR entity
4993 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4994 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4997 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5001 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5004 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
5005 RSurf_ActiveModelEntity(ent, false, false, false);
5006 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
5007 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5011 // not really the right mode, but this will disable any silly stencil features
5012 R_Shadow_RenderMode_End();
5014 // set up ortho view for rendering this pass
5015 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5016 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5017 //GL_ScissorTest(true);
5018 //R_EntityMatrix(&identitymatrix);
5019 //R_Mesh_ResetTextureState();
5020 R_ResetViewRendering2D(fbo, depthtexture, colortexture);
5022 // set up a darkening blend on shadowed areas
5023 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5024 //GL_DepthRange(0, 1);
5025 //GL_DepthTest(false);
5026 //GL_DepthMask(false);
5027 //GL_PolygonOffset(0, 0);CHECKGLERROR
5028 GL_Color(0, 0, 0, r_shadows_darken.value);
5029 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5030 //GL_DepthFunc(GL_ALWAYS);
5031 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5033 // apply the blend to the shadowed areas
5034 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5035 R_SetupShader_Generic_NoTexture(false, true);
5036 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5038 // restore the viewport
5039 R_SetViewport(&r_refdef.view.viewport);
5041 // restore other state to normal
5042 //R_Shadow_RenderMode_End();
5045 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5048 vec3_t centerorigin;
5050 // if it's too close, skip it
5051 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5053 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5056 if (usequery && r_numqueries + 2 <= r_maxqueries)
5058 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5059 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5060 // 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
5061 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5063 switch(vid.renderpath)
5065 case RENDERPATH_GL11:
5066 case RENDERPATH_GL13:
5067 case RENDERPATH_GL20:
5068 case RENDERPATH_GLES1:
5069 case RENDERPATH_GLES2:
5070 #ifdef GL_SAMPLES_PASSED_ARB
5072 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5073 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5074 GL_DepthFunc(GL_ALWAYS);
5075 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5076 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
5077 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5078 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5079 GL_DepthFunc(GL_LEQUAL);
5080 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5081 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5082 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
5083 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5084 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5088 case RENDERPATH_D3D9:
5089 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5091 case RENDERPATH_D3D10:
5092 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5094 case RENDERPATH_D3D11:
5095 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5097 case RENDERPATH_SOFT:
5098 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5102 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5105 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5107 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5110 GLint allpixels = 0, visiblepixels = 0;
5111 // now we have to check the query result
5112 if (rtlight->corona_queryindex_visiblepixels)
5114 switch(vid.renderpath)
5116 case RENDERPATH_GL11:
5117 case RENDERPATH_GL13:
5118 case RENDERPATH_GL20:
5119 case RENDERPATH_GLES1:
5120 case RENDERPATH_GLES2:
5121 #ifdef GL_SAMPLES_PASSED_ARB
5123 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5124 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5128 case RENDERPATH_D3D9:
5129 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5131 case RENDERPATH_D3D10:
5132 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5134 case RENDERPATH_D3D11:
5135 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5137 case RENDERPATH_SOFT:
5138 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5141 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
5142 if (visiblepixels < 1 || allpixels < 1)
5144 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5145 cscale *= rtlight->corona_visibility;
5149 // FIXME: these traces should scan all render entities instead of cl.world
5150 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1)
5153 VectorScale(rtlight->currentcolor, cscale, color);
5154 if (VectorLength(color) > (1.0f / 256.0f))
5157 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
5160 VectorNegate(color, color);
5161 GL_BlendEquationSubtract(true);
5163 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5164 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);
5165 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5167 GL_BlendEquationSubtract(false);
5171 void R_Shadow_DrawCoronas(void)
5174 qboolean usequery = false;
5179 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
5181 if (r_fb.water.renderingscene)
5183 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5184 R_EntityMatrix(&identitymatrix);
5186 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5188 // check occlusion of coronas
5189 // use GL_ARB_occlusion_query if available
5190 // otherwise use raytraces
5192 switch (vid.renderpath)
5194 case RENDERPATH_GL11:
5195 case RENDERPATH_GL13:
5196 case RENDERPATH_GL20:
5197 case RENDERPATH_GLES1:
5198 case RENDERPATH_GLES2:
5199 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
5200 #ifdef GL_SAMPLES_PASSED_ARB
5203 GL_ColorMask(0,0,0,0);
5204 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
5205 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
5208 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
5209 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
5211 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
5214 RSurf_ActiveWorldEntity();
5215 GL_BlendFunc(GL_ONE, GL_ZERO);
5216 GL_CullFace(GL_NONE);
5217 GL_DepthMask(false);
5218 GL_DepthRange(0, 1);
5219 GL_PolygonOffset(0, 0);
5221 R_Mesh_ResetTextureState();
5222 R_SetupShader_Generic_NoTexture(false, false);
5226 case RENDERPATH_D3D9:
5228 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5230 case RENDERPATH_D3D10:
5231 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5233 case RENDERPATH_D3D11:
5234 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5236 case RENDERPATH_SOFT:
5238 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5241 for (lightindex = 0;lightindex < range;lightindex++)
5243 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5246 rtlight = &light->rtlight;
5247 rtlight->corona_visibility = 0;
5248 rtlight->corona_queryindex_visiblepixels = 0;
5249 rtlight->corona_queryindex_allpixels = 0;
5250 if (!(rtlight->flags & flag))
5252 if (rtlight->corona <= 0)
5254 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
5256 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5258 for (i = 0;i < r_refdef.scene.numlights;i++)
5260 rtlight = r_refdef.scene.lights[i];
5261 rtlight->corona_visibility = 0;
5262 rtlight->corona_queryindex_visiblepixels = 0;
5263 rtlight->corona_queryindex_allpixels = 0;
5264 if (!(rtlight->flags & flag))
5266 if (rtlight->corona <= 0)
5268 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5271 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5273 // now draw the coronas using the query data for intensity info
5274 for (lightindex = 0;lightindex < range;lightindex++)
5276 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5279 rtlight = &light->rtlight;
5280 if (rtlight->corona_visibility <= 0)
5282 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5284 for (i = 0;i < r_refdef.scene.numlights;i++)
5286 rtlight = r_refdef.scene.lights[i];
5287 if (rtlight->corona_visibility <= 0)
5289 if (gl_flashblend.integer)
5290 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
5292 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5298 static dlight_t *R_Shadow_NewWorldLight(void)
5300 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
5303 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)
5306 // validate parameters
5307 if (style < 0 || style >= MAX_LIGHTSTYLES)
5309 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
5315 // copy to light properties
5316 VectorCopy(origin, light->origin);
5317 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
5318 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
5319 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
5321 light->color[0] = max(color[0], 0);
5322 light->color[1] = max(color[1], 0);
5323 light->color[2] = max(color[2], 0);
5325 light->color[0] = color[0];
5326 light->color[1] = color[1];
5327 light->color[2] = color[2];
5328 light->radius = max(radius, 0);
5329 light->style = style;
5330 light->shadow = shadowenable;
5331 light->corona = corona;
5332 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
5333 light->coronasizescale = coronasizescale;
5334 light->ambientscale = ambientscale;
5335 light->diffusescale = diffusescale;
5336 light->specularscale = specularscale;
5337 light->flags = flags;
5339 // update renderable light data
5340 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
5341 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);
5344 static void R_Shadow_FreeWorldLight(dlight_t *light)
5346 if (r_shadow_selectedlight == light)
5347 r_shadow_selectedlight = NULL;
5348 R_RTLight_Uncompile(&light->rtlight);
5349 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
5352 void R_Shadow_ClearWorldLights(void)
5356 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5357 for (lightindex = 0;lightindex < range;lightindex++)
5359 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5361 R_Shadow_FreeWorldLight(light);
5363 r_shadow_selectedlight = NULL;
5366 static void R_Shadow_SelectLight(dlight_t *light)
5368 if (r_shadow_selectedlight)
5369 r_shadow_selectedlight->selected = false;
5370 r_shadow_selectedlight = light;
5371 if (r_shadow_selectedlight)
5372 r_shadow_selectedlight->selected = true;
5375 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5377 // this is never batched (there can be only one)
5379 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
5380 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5381 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5384 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5389 skinframe_t *skinframe;
5392 // this is never batched (due to the ent parameter changing every time)
5393 // so numsurfaces == 1 and surfacelist[0] == lightnumber
5394 const dlight_t *light = (dlight_t *)ent;
5397 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
5400 VectorScale(light->color, intensity, spritecolor);
5401 if (VectorLength(spritecolor) < 0.1732f)
5402 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
5403 if (VectorLength(spritecolor) > 1.0f)
5404 VectorNormalize(spritecolor);
5406 // draw light sprite
5407 if (light->cubemapname[0] && !light->shadow)
5408 skinframe = r_editlights_sprcubemapnoshadowlight;
5409 else if (light->cubemapname[0])
5410 skinframe = r_editlights_sprcubemaplight;
5411 else if (!light->shadow)
5412 skinframe = r_editlights_sprnoshadowlight;
5414 skinframe = r_editlights_sprlight;
5416 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);
5417 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5419 // draw selection sprite if light is selected
5420 if (light->selected)
5422 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5423 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5424 // VorteX todo: add normalmode/realtime mode light overlay sprites?
5428 void R_Shadow_DrawLightSprites(void)
5432 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5433 for (lightindex = 0;lightindex < range;lightindex++)
5435 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5437 R_MeshQueue_AddTransparent(MESHQUEUE_SORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
5439 if (!r_editlights_lockcursor)
5440 R_MeshQueue_AddTransparent(MESHQUEUE_SORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
5443 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
5448 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
5449 if (lightindex >= range)
5451 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5454 rtlight = &light->rtlight;
5455 //if (!(rtlight->flags & flag))
5457 VectorCopy(rtlight->shadoworigin, origin);
5458 *radius = rtlight->radius;
5459 VectorCopy(rtlight->color, color);
5463 static void R_Shadow_SelectLightInView(void)
5465 float bestrating, rating, temp[3];
5469 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5473 if (r_editlights_lockcursor)
5475 for (lightindex = 0;lightindex < range;lightindex++)
5477 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5480 VectorSubtract(light->origin, r_refdef.view.origin, temp);
5481 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
5484 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
5485 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction == 1.0f)
5487 bestrating = rating;
5492 R_Shadow_SelectLight(best);
5495 void R_Shadow_LoadWorldLights(void)
5497 int n, a, style, shadow, flags;
5498 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
5499 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
5500 if (cl.worldmodel == NULL)
5502 Con_Print("No map loaded.\n");
5505 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5506 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5516 for (;COM_Parse(t, true) && strcmp(
5517 if (COM_Parse(t, true))
5519 if (com_token[0] == '!')
5522 origin[0] = atof(com_token+1);
5525 origin[0] = atof(com_token);
5530 while (*s && *s != '\n' && *s != '\r')
5536 // check for modifier flags
5543 #if _MSC_VER >= 1400
5544 #define sscanf sscanf_s
5546 cubemapname[sizeof(cubemapname)-1] = 0;
5547 #if MAX_QPATH != 128
5548 #error update this code if MAX_QPATH changes
5550 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
5551 #if _MSC_VER >= 1400
5552 , sizeof(cubemapname)
5554 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5557 flags = LIGHTFLAG_REALTIMEMODE;
5565 coronasizescale = 0.25f;
5567 VectorClear(angles);
5570 if (a < 9 || !strcmp(cubemapname, "\"\""))
5572 // remove quotes on cubemapname
5573 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5576 namelen = strlen(cubemapname) - 2;
5577 memmove(cubemapname, cubemapname + 1, namelen);
5578 cubemapname[namelen] = '\0';
5582 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);
5585 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5593 Con_Printf("invalid rtlights file \"%s\"\n", name);
5594 Mem_Free(lightsstring);
5598 void R_Shadow_SaveWorldLights(void)
5602 size_t bufchars, bufmaxchars;
5604 char name[MAX_QPATH];
5605 char line[MAX_INPUTLINE];
5606 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5607 // I hate lines which are 3 times my screen size :( --blub
5610 if (cl.worldmodel == NULL)
5612 Con_Print("No map loaded.\n");
5615 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5616 bufchars = bufmaxchars = 0;
5618 for (lightindex = 0;lightindex < range;lightindex++)
5620 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5623 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5624 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);
5625 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5626 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]);
5628 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);
5629 if (bufchars + strlen(line) > bufmaxchars)
5631 bufmaxchars = bufchars + strlen(line) + 2048;
5633 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5637 memcpy(buf, oldbuf, bufchars);
5643 memcpy(buf + bufchars, line, strlen(line));
5644 bufchars += strlen(line);
5648 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5653 void R_Shadow_LoadLightsFile(void)
5656 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5657 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5658 if (cl.worldmodel == NULL)
5660 Con_Print("No map loaded.\n");
5663 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5664 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5672 while (*s && *s != '\n' && *s != '\r')
5678 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);
5682 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);
5685 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5686 radius = bound(15, radius, 4096);
5687 VectorScale(color, (2.0f / (8388608.0f)), color);
5688 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5696 Con_Printf("invalid lights file \"%s\"\n", name);
5697 Mem_Free(lightsstring);
5701 // tyrlite/hmap2 light types in the delay field
5702 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5704 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5716 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5717 char key[256], value[MAX_INPUTLINE];
5720 if (cl.worldmodel == NULL)
5722 Con_Print("No map loaded.\n");
5725 // try to load a .ent file first
5726 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5727 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5728 // and if that is not found, fall back to the bsp file entity string
5730 data = cl.worldmodel->brush.entities;
5733 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
5735 type = LIGHTTYPE_MINUSX;
5736 origin[0] = origin[1] = origin[2] = 0;
5737 originhack[0] = originhack[1] = originhack[2] = 0;
5738 angles[0] = angles[1] = angles[2] = 0;
5739 color[0] = color[1] = color[2] = 1;
5740 light[0] = light[1] = light[2] = 1;light[3] = 300;
5741 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5751 if (!COM_ParseToken_Simple(&data, false, false, true))
5753 if (com_token[0] == '}')
5754 break; // end of entity
5755 if (com_token[0] == '_')
5756 strlcpy(key, com_token + 1, sizeof(key));
5758 strlcpy(key, com_token, sizeof(key));
5759 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5760 key[strlen(key)-1] = 0;
5761 if (!COM_ParseToken_Simple(&data, false, false, true))
5763 strlcpy(value, com_token, sizeof(value));
5765 // now that we have the key pair worked out...
5766 if (!strcmp("light", key))
5768 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5772 light[0] = vec[0] * (1.0f / 256.0f);
5773 light[1] = vec[0] * (1.0f / 256.0f);
5774 light[2] = vec[0] * (1.0f / 256.0f);
5780 light[0] = vec[0] * (1.0f / 255.0f);
5781 light[1] = vec[1] * (1.0f / 255.0f);
5782 light[2] = vec[2] * (1.0f / 255.0f);
5786 else if (!strcmp("delay", key))
5788 else if (!strcmp("origin", key))
5789 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5790 else if (!strcmp("angle", key))
5791 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5792 else if (!strcmp("angles", key))
5793 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5794 else if (!strcmp("color", key))
5795 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5796 else if (!strcmp("wait", key))
5797 fadescale = atof(value);
5798 else if (!strcmp("classname", key))
5800 if (!strncmp(value, "light", 5))
5803 if (!strcmp(value, "light_fluoro"))
5808 overridecolor[0] = 1;
5809 overridecolor[1] = 1;
5810 overridecolor[2] = 1;
5812 if (!strcmp(value, "light_fluorospark"))
5817 overridecolor[0] = 1;
5818 overridecolor[1] = 1;
5819 overridecolor[2] = 1;
5821 if (!strcmp(value, "light_globe"))
5826 overridecolor[0] = 1;
5827 overridecolor[1] = 0.8;
5828 overridecolor[2] = 0.4;
5830 if (!strcmp(value, "light_flame_large_yellow"))
5835 overridecolor[0] = 1;
5836 overridecolor[1] = 0.5;
5837 overridecolor[2] = 0.1;
5839 if (!strcmp(value, "light_flame_small_yellow"))
5844 overridecolor[0] = 1;
5845 overridecolor[1] = 0.5;
5846 overridecolor[2] = 0.1;
5848 if (!strcmp(value, "light_torch_small_white"))
5853 overridecolor[0] = 1;
5854 overridecolor[1] = 0.5;
5855 overridecolor[2] = 0.1;
5857 if (!strcmp(value, "light_torch_small_walltorch"))
5862 overridecolor[0] = 1;
5863 overridecolor[1] = 0.5;
5864 overridecolor[2] = 0.1;
5868 else if (!strcmp("style", key))
5869 style = atoi(value);
5870 else if (!strcmp("skin", key))
5871 skin = (int)atof(value);
5872 else if (!strcmp("pflags", key))
5873 pflags = (int)atof(value);
5874 //else if (!strcmp("effects", key))
5875 // effects = (int)atof(value);
5876 else if (cl.worldmodel->type == mod_brushq3)
5878 if (!strcmp("scale", key))
5879 lightscale = atof(value);
5880 if (!strcmp("fade", key))
5881 fadescale = atof(value);
5886 if (lightscale <= 0)
5890 if (color[0] == color[1] && color[0] == color[2])
5892 color[0] *= overridecolor[0];
5893 color[1] *= overridecolor[1];
5894 color[2] *= overridecolor[2];
5896 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5897 color[0] = color[0] * light[0];
5898 color[1] = color[1] * light[1];
5899 color[2] = color[2] * light[2];
5902 case LIGHTTYPE_MINUSX:
5904 case LIGHTTYPE_RECIPX:
5906 VectorScale(color, (1.0f / 16.0f), color);
5908 case LIGHTTYPE_RECIPXX:
5910 VectorScale(color, (1.0f / 16.0f), color);
5913 case LIGHTTYPE_NONE:
5917 case LIGHTTYPE_MINUSXX:
5920 VectorAdd(origin, originhack, origin);
5922 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);
5925 Mem_Free(entfiledata);
5929 static void R_Shadow_SetCursorLocationForView(void)
5932 vec3_t dest, endpos;
5934 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5935 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true);
5936 if (trace.fraction < 1)
5938 dist = trace.fraction * r_editlights_cursordistance.value;
5939 push = r_editlights_cursorpushback.value;
5943 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5944 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5948 VectorClear( endpos );
5950 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5951 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5952 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5955 void R_Shadow_UpdateWorldLightSelection(void)
5957 if (r_editlights.integer)
5959 R_Shadow_SetCursorLocationForView();
5960 R_Shadow_SelectLightInView();
5963 R_Shadow_SelectLight(NULL);
5966 static void R_Shadow_EditLights_Clear_f(void)
5968 R_Shadow_ClearWorldLights();
5971 void R_Shadow_EditLights_Reload_f(void)
5975 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5976 R_Shadow_ClearWorldLights();
5977 R_Shadow_LoadWorldLights();
5978 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5980 R_Shadow_LoadLightsFile();
5981 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5982 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5986 static void R_Shadow_EditLights_Save_f(void)
5990 R_Shadow_SaveWorldLights();
5993 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5995 R_Shadow_ClearWorldLights();
5996 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5999 static void R_Shadow_EditLights_ImportLightsFile_f(void)
6001 R_Shadow_ClearWorldLights();
6002 R_Shadow_LoadLightsFile();
6005 static void R_Shadow_EditLights_Spawn_f(void)
6008 if (!r_editlights.integer)
6010 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6013 if (Cmd_Argc() != 1)
6015 Con_Print("r_editlights_spawn does not take parameters\n");
6018 color[0] = color[1] = color[2] = 1;
6019 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6022 static void R_Shadow_EditLights_Edit_f(void)
6024 vec3_t origin, angles, color;
6025 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6026 int style, shadows, flags, normalmode, realtimemode;
6027 char cubemapname[MAX_INPUTLINE];
6028 if (!r_editlights.integer)
6030 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6033 if (!r_shadow_selectedlight)
6035 Con_Print("No selected light.\n");
6038 VectorCopy(r_shadow_selectedlight->origin, origin);
6039 VectorCopy(r_shadow_selectedlight->angles, angles);
6040 VectorCopy(r_shadow_selectedlight->color, color);
6041 radius = r_shadow_selectedlight->radius;
6042 style = r_shadow_selectedlight->style;
6043 if (r_shadow_selectedlight->cubemapname)
6044 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6047 shadows = r_shadow_selectedlight->shadow;
6048 corona = r_shadow_selectedlight->corona;
6049 coronasizescale = r_shadow_selectedlight->coronasizescale;
6050 ambientscale = r_shadow_selectedlight->ambientscale;
6051 diffusescale = r_shadow_selectedlight->diffusescale;
6052 specularscale = r_shadow_selectedlight->specularscale;
6053 flags = r_shadow_selectedlight->flags;
6054 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6055 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6056 if (!strcmp(Cmd_Argv(1), "origin"))
6058 if (Cmd_Argc() != 5)
6060 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6063 origin[0] = atof(Cmd_Argv(2));
6064 origin[1] = atof(Cmd_Argv(3));
6065 origin[2] = atof(Cmd_Argv(4));
6067 else if (!strcmp(Cmd_Argv(1), "originscale"))
6069 if (Cmd_Argc() != 5)
6071 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6074 origin[0] *= atof(Cmd_Argv(2));
6075 origin[1] *= atof(Cmd_Argv(3));
6076 origin[2] *= atof(Cmd_Argv(4));
6078 else if (!strcmp(Cmd_Argv(1), "originx"))
6080 if (Cmd_Argc() != 3)
6082 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6085 origin[0] = atof(Cmd_Argv(2));
6087 else if (!strcmp(Cmd_Argv(1), "originy"))
6089 if (Cmd_Argc() != 3)
6091 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6094 origin[1] = atof(Cmd_Argv(2));
6096 else if (!strcmp(Cmd_Argv(1), "originz"))
6098 if (Cmd_Argc() != 3)
6100 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6103 origin[2] = atof(Cmd_Argv(2));
6105 else if (!strcmp(Cmd_Argv(1), "move"))
6107 if (Cmd_Argc() != 5)
6109 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6112 origin[0] += atof(Cmd_Argv(2));
6113 origin[1] += atof(Cmd_Argv(3));
6114 origin[2] += atof(Cmd_Argv(4));
6116 else if (!strcmp(Cmd_Argv(1), "movex"))
6118 if (Cmd_Argc() != 3)
6120 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6123 origin[0] += atof(Cmd_Argv(2));
6125 else if (!strcmp(Cmd_Argv(1), "movey"))
6127 if (Cmd_Argc() != 3)
6129 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6132 origin[1] += atof(Cmd_Argv(2));
6134 else if (!strcmp(Cmd_Argv(1), "movez"))
6136 if (Cmd_Argc() != 3)
6138 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6141 origin[2] += atof(Cmd_Argv(2));
6143 else if (!strcmp(Cmd_Argv(1), "angles"))
6145 if (Cmd_Argc() != 5)
6147 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6150 angles[0] = atof(Cmd_Argv(2));
6151 angles[1] = atof(Cmd_Argv(3));
6152 angles[2] = atof(Cmd_Argv(4));
6154 else if (!strcmp(Cmd_Argv(1), "anglesx"))
6156 if (Cmd_Argc() != 3)
6158 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6161 angles[0] = atof(Cmd_Argv(2));
6163 else if (!strcmp(Cmd_Argv(1), "anglesy"))
6165 if (Cmd_Argc() != 3)
6167 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6170 angles[1] = atof(Cmd_Argv(2));
6172 else if (!strcmp(Cmd_Argv(1), "anglesz"))
6174 if (Cmd_Argc() != 3)
6176 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6179 angles[2] = atof(Cmd_Argv(2));
6181 else if (!strcmp(Cmd_Argv(1), "color"))
6183 if (Cmd_Argc() != 5)
6185 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
6188 color[0] = atof(Cmd_Argv(2));
6189 color[1] = atof(Cmd_Argv(3));
6190 color[2] = atof(Cmd_Argv(4));
6192 else if (!strcmp(Cmd_Argv(1), "radius"))
6194 if (Cmd_Argc() != 3)
6196 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6199 radius = atof(Cmd_Argv(2));
6201 else if (!strcmp(Cmd_Argv(1), "colorscale"))
6203 if (Cmd_Argc() == 3)
6205 double scale = atof(Cmd_Argv(2));
6212 if (Cmd_Argc() != 5)
6214 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
6217 color[0] *= atof(Cmd_Argv(2));
6218 color[1] *= atof(Cmd_Argv(3));
6219 color[2] *= atof(Cmd_Argv(4));
6222 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
6224 if (Cmd_Argc() != 3)
6226 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6229 radius *= atof(Cmd_Argv(2));
6231 else if (!strcmp(Cmd_Argv(1), "style"))
6233 if (Cmd_Argc() != 3)
6235 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6238 style = atoi(Cmd_Argv(2));
6240 else if (!strcmp(Cmd_Argv(1), "cubemap"))
6244 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6247 if (Cmd_Argc() == 3)
6248 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
6252 else if (!strcmp(Cmd_Argv(1), "shadows"))
6254 if (Cmd_Argc() != 3)
6256 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6259 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6261 else if (!strcmp(Cmd_Argv(1), "corona"))
6263 if (Cmd_Argc() != 3)
6265 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6268 corona = atof(Cmd_Argv(2));
6270 else if (!strcmp(Cmd_Argv(1), "coronasize"))
6272 if (Cmd_Argc() != 3)
6274 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6277 coronasizescale = atof(Cmd_Argv(2));
6279 else if (!strcmp(Cmd_Argv(1), "ambient"))
6281 if (Cmd_Argc() != 3)
6283 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6286 ambientscale = atof(Cmd_Argv(2));
6288 else if (!strcmp(Cmd_Argv(1), "diffuse"))
6290 if (Cmd_Argc() != 3)
6292 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6295 diffusescale = atof(Cmd_Argv(2));
6297 else if (!strcmp(Cmd_Argv(1), "specular"))
6299 if (Cmd_Argc() != 3)
6301 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6304 specularscale = atof(Cmd_Argv(2));
6306 else if (!strcmp(Cmd_Argv(1), "normalmode"))
6308 if (Cmd_Argc() != 3)
6310 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6313 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6315 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
6317 if (Cmd_Argc() != 3)
6319 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6322 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6326 Con_Print("usage: r_editlights_edit [property] [value]\n");
6327 Con_Print("Selected light's properties:\n");
6328 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6329 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6330 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6331 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
6332 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
6333 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
6334 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
6335 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
6336 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
6337 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
6338 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
6339 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
6340 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
6341 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
6344 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
6345 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6348 static void R_Shadow_EditLights_EditAll_f(void)
6351 dlight_t *light, *oldselected;
6354 if (!r_editlights.integer)
6356 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
6360 oldselected = r_shadow_selectedlight;
6361 // EditLights doesn't seem to have a "remove" command or something so:
6362 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6363 for (lightindex = 0;lightindex < range;lightindex++)
6365 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6368 R_Shadow_SelectLight(light);
6369 R_Shadow_EditLights_Edit_f();
6371 // return to old selected (to not mess editing once selection is locked)
6372 R_Shadow_SelectLight(oldselected);
6375 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
6377 int lightnumber, lightcount;
6378 size_t lightindex, range;
6382 if (!r_editlights.integer)
6384 x = vid_conwidth.value - 240;
6386 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
6389 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6390 for (lightindex = 0;lightindex < range;lightindex++)
6392 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6395 if (light == r_shadow_selectedlight)
6396 lightnumber = lightindex;
6399 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;
6400 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;
6402 if (r_shadow_selectedlight == NULL)
6404 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;
6405 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;
6406 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;
6407 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;
6408 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;
6409 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;
6410 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;
6411 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;
6412 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;
6413 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;
6414 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;
6415 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;
6416 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;
6417 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;
6418 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;
6421 static void R_Shadow_EditLights_ToggleShadow_f(void)
6423 if (!r_editlights.integer)
6425 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6428 if (!r_shadow_selectedlight)
6430 Con_Print("No selected light.\n");
6433 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);
6436 static void R_Shadow_EditLights_ToggleCorona_f(void)
6438 if (!r_editlights.integer)
6440 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6443 if (!r_shadow_selectedlight)
6445 Con_Print("No selected light.\n");
6448 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);
6451 static void R_Shadow_EditLights_Remove_f(void)
6453 if (!r_editlights.integer)
6455 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
6458 if (!r_shadow_selectedlight)
6460 Con_Print("No selected light.\n");
6463 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
6464 r_shadow_selectedlight = NULL;
6467 static void R_Shadow_EditLights_Help_f(void)
6470 "Documentation on r_editlights system:\n"
6472 "r_editlights : enable/disable editing mode\n"
6473 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
6474 "r_editlights_cursorpushback : push back cursor this far from surface\n"
6475 "r_editlights_cursorpushoff : push cursor off surface this far\n"
6476 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
6477 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
6479 "r_editlights_help : this help\n"
6480 "r_editlights_clear : remove all lights\n"
6481 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
6482 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
6483 "r_editlights_save : save to .rtlights file\n"
6484 "r_editlights_spawn : create a light with default settings\n"
6485 "r_editlights_edit command : edit selected light - more documentation below\n"
6486 "r_editlights_remove : remove selected light\n"
6487 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
6488 "r_editlights_importlightentitiesfrommap : reload light entities\n"
6489 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
6491 "origin x y z : set light location\n"
6492 "originx x: set x component of light location\n"
6493 "originy y: set y component of light location\n"
6494 "originz z: set z component of light location\n"
6495 "move x y z : adjust light location\n"
6496 "movex x: adjust x component of light location\n"
6497 "movey y: adjust y component of light location\n"
6498 "movez z: adjust z component of light location\n"
6499 "angles x y z : set light angles\n"
6500 "anglesx x: set x component of light angles\n"
6501 "anglesy y: set y component of light angles\n"
6502 "anglesz z: set z component of light angles\n"
6503 "color r g b : set color of light (can be brighter than 1 1 1)\n"
6504 "radius radius : set radius (size) of light\n"
6505 "colorscale grey : multiply color of light (1 does nothing)\n"
6506 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
6507 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
6508 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
6509 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
6510 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
6511 "cubemap basename : set filter cubemap of light (not yet supported)\n"
6512 "shadows 1/0 : turn on/off shadows\n"
6513 "corona n : set corona intensity\n"
6514 "coronasize n : set corona size (0-1)\n"
6515 "ambient n : set ambient intensity (0-1)\n"
6516 "diffuse n : set diffuse intensity (0-1)\n"
6517 "specular n : set specular intensity (0-1)\n"
6518 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6519 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6520 "<nothing> : print light properties to console\n"
6524 static void R_Shadow_EditLights_CopyInfo_f(void)
6526 if (!r_editlights.integer)
6528 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
6531 if (!r_shadow_selectedlight)
6533 Con_Print("No selected light.\n");
6536 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6537 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6538 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6539 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6540 if (r_shadow_selectedlight->cubemapname)
6541 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6543 r_shadow_bufferlight.cubemapname[0] = 0;
6544 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6545 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6546 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6547 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6548 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6549 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6550 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6553 static void R_Shadow_EditLights_PasteInfo_f(void)
6555 if (!r_editlights.integer)
6557 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6560 if (!r_shadow_selectedlight)
6562 Con_Print("No selected light.\n");
6565 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);
6568 static void R_Shadow_EditLights_Lock_f(void)
6570 if (!r_editlights.integer)
6572 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6575 if (r_editlights_lockcursor)
6577 r_editlights_lockcursor = false;
6580 if (!r_shadow_selectedlight)
6582 Con_Print("No selected light to lock on.\n");
6585 r_editlights_lockcursor = true;
6588 static void R_Shadow_EditLights_Init(void)
6590 Cvar_RegisterVariable(&r_editlights);
6591 Cvar_RegisterVariable(&r_editlights_cursordistance);
6592 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6593 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6594 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6595 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6596 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6597 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6598 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)");
6599 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6600 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6601 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6602 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)");
6603 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6604 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6605 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6606 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6607 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6608 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6609 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)");
6610 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6616 =============================================================================
6620 =============================================================================
6623 void R_LightPoint(vec3_t color, const vec3_t p, const int flags)
6625 int i, numlights, flag;
6626 float f, relativepoint[3], dist, dist2, lightradius2;
6631 if (r_fullbright.integer)
6633 VectorSet(color, 1, 1, 1);
6639 if (flags & LP_LIGHTMAP)
6641 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6643 VectorClear(diffuse);
6644 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, color, diffuse, n);
6645 VectorAdd(color, diffuse, color);
6648 VectorSet(color, 1, 1, 1);
6649 color[0] += r_refdef.scene.ambient;
6650 color[1] += r_refdef.scene.ambient;
6651 color[2] += r_refdef.scene.ambient;
6654 if (flags & LP_RTWORLD)
6656 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6657 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6658 for (i = 0; i < numlights; i++)
6660 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6663 light = &dlight->rtlight;
6664 if (!(light->flags & flag))
6667 lightradius2 = light->radius * light->radius;
6668 VectorSubtract(light->shadoworigin, p, relativepoint);
6669 dist2 = VectorLength2(relativepoint);
6670 if (dist2 >= lightradius2)
6672 dist = sqrt(dist2) / light->radius;
6673 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
6676 // todo: add to both ambient and diffuse
6677 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction == 1)
6678 VectorMA(color, f, light->currentcolor, color);
6681 if (flags & LP_DYNLIGHT)
6684 for (i = 0;i < r_refdef.scene.numlights;i++)
6686 light = r_refdef.scene.lights[i];
6688 lightradius2 = light->radius * light->radius;
6689 VectorSubtract(light->shadoworigin, p, relativepoint);
6690 dist2 = VectorLength2(relativepoint);
6691 if (dist2 >= lightradius2)
6693 dist = sqrt(dist2) / light->radius;
6694 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
6697 // todo: add to both ambient and diffuse
6698 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction == 1)
6699 VectorMA(color, f, light->color, color);
6704 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
6706 int i, numlights, flag;
6709 float relativepoint[3];
6718 if (r_fullbright.integer)
6720 VectorSet(ambient, 1, 1, 1);
6721 VectorClear(diffuse);
6722 VectorClear(lightdir);
6726 if (flags == LP_LIGHTMAP)
6728 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6729 VectorClear(diffuse);
6730 VectorClear(lightdir);
6731 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6732 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
6734 VectorSet(ambient, 1, 1, 1);
6738 memset(sample, 0, sizeof(sample));
6739 VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6741 if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6744 VectorClear(tempambient);
6746 VectorClear(relativepoint);
6747 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6748 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
6749 VectorScale(color, r_refdef.lightmapintensity, color);
6750 VectorAdd(sample, tempambient, sample);
6751 VectorMA(sample , 0.5f , color, sample );
6752 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6753 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6754 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6755 // calculate a weighted average light direction as well
6756 intensity = VectorLength(color);
6757 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6760 if (flags & LP_RTWORLD)
6762 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6763 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6764 for (i = 0; i < numlights; i++)
6766 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6769 light = &dlight->rtlight;
6770 if (!(light->flags & flag))
6773 lightradius2 = light->radius * light->radius;
6774 VectorSubtract(light->shadoworigin, p, relativepoint);
6775 dist2 = VectorLength2(relativepoint);
6776 if (dist2 >= lightradius2)
6778 dist = sqrt(dist2) / light->radius;
6779 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6780 if (intensity <= 0.0f)
6782 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1)
6784 // scale down intensity to add to both ambient and diffuse
6785 //intensity *= 0.5f;
6786 VectorNormalize(relativepoint);
6787 VectorScale(light->currentcolor, intensity, color);
6788 VectorMA(sample , 0.5f , color, sample );
6789 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6790 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6791 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6792 // calculate a weighted average light direction as well
6793 intensity *= VectorLength(color);
6794 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6796 // FIXME: sample bouncegrid too!
6799 if (flags & LP_DYNLIGHT)
6802 for (i = 0;i < r_refdef.scene.numlights;i++)
6804 light = r_refdef.scene.lights[i];
6806 lightradius2 = light->radius * light->radius;
6807 VectorSubtract(light->shadoworigin, p, relativepoint);
6808 dist2 = VectorLength2(relativepoint);
6809 if (dist2 >= lightradius2)
6811 dist = sqrt(dist2) / light->radius;
6812 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6813 if (intensity <= 0.0f)
6815 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1)
6817 // scale down intensity to add to both ambient and diffuse
6818 //intensity *= 0.5f;
6819 VectorNormalize(relativepoint);
6820 VectorScale(light->currentcolor, intensity, color);
6821 VectorMA(sample , 0.5f , color, sample );
6822 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6823 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6824 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6825 // calculate a weighted average light direction as well
6826 intensity *= VectorLength(color);
6827 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6831 // calculate the direction we'll use to reduce the sample to a directional light source
6832 VectorCopy(sample + 12, dir);
6833 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
6834 VectorNormalize(dir);
6835 // extract the diffuse color along the chosen direction and scale it
6836 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
6837 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
6838 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
6839 // subtract some of diffuse from ambient
6840 VectorMA(sample, -0.333f, diffuse, ambient);
6841 // store the normalized lightdir
6842 VectorCopy(dir, lightdir);