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:
500 if(R_CompileShader_CheckStaticParms())
504 qboolean R_Shadow_ShadowMappingEnabled(void)
506 switch (r_shadow_shadowmode)
508 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
515 static void R_Shadow_FreeShadowMaps(void)
517 R_Shadow_SetShadowMode();
519 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
523 if (r_shadow_shadowmap2ddepthtexture)
524 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
525 r_shadow_shadowmap2ddepthtexture = NULL;
527 if (r_shadow_shadowmap2ddepthbuffer)
528 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
529 r_shadow_shadowmap2ddepthbuffer = NULL;
531 if (r_shadow_shadowmapvsdcttexture)
532 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
533 r_shadow_shadowmapvsdcttexture = NULL;
536 static void r_shadow_start(void)
538 // allocate vertex processing arrays
539 r_shadow_bouncegridpixels = NULL;
540 r_shadow_bouncegridhighpixels = NULL;
541 r_shadow_bouncegridnumpixels = 0;
542 r_shadow_bouncegridtexture = NULL;
543 r_shadow_bouncegriddirectional = false;
544 r_shadow_attenuationgradienttexture = NULL;
545 r_shadow_attenuation2dtexture = NULL;
546 r_shadow_attenuation3dtexture = NULL;
547 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
548 r_shadow_shadowmap2ddepthtexture = NULL;
549 r_shadow_shadowmap2ddepthbuffer = NULL;
550 r_shadow_shadowmapvsdcttexture = NULL;
551 r_shadow_shadowmapmaxsize = 0;
552 r_shadow_shadowmapsize = 0;
553 r_shadow_shadowmaplod = 0;
554 r_shadow_shadowmapfilterquality = -1;
555 r_shadow_shadowmapdepthbits = 0;
556 r_shadow_shadowmapvsdct = false;
557 r_shadow_shadowmapsampler = false;
558 r_shadow_shadowmappcf = 0;
561 R_Shadow_FreeShadowMaps();
563 r_shadow_texturepool = NULL;
564 r_shadow_filters_texturepool = NULL;
565 R_Shadow_ValidateCvars();
566 R_Shadow_MakeTextures();
567 maxshadowtriangles = 0;
568 shadowelements = NULL;
569 maxshadowvertices = 0;
570 shadowvertex3f = NULL;
578 shadowmarklist = NULL;
583 shadowsideslist = NULL;
584 r_shadow_buffer_numleafpvsbytes = 0;
585 r_shadow_buffer_visitingleafpvs = NULL;
586 r_shadow_buffer_leafpvs = NULL;
587 r_shadow_buffer_leaflist = NULL;
588 r_shadow_buffer_numsurfacepvsbytes = 0;
589 r_shadow_buffer_surfacepvs = NULL;
590 r_shadow_buffer_surfacelist = NULL;
591 r_shadow_buffer_surfacesides = NULL;
592 r_shadow_buffer_numshadowtrispvsbytes = 0;
593 r_shadow_buffer_shadowtrispvs = NULL;
594 r_shadow_buffer_numlighttrispvsbytes = 0;
595 r_shadow_buffer_lighttrispvs = NULL;
597 r_shadow_usingdeferredprepass = false;
598 r_shadow_prepass_width = r_shadow_prepass_height = 0;
601 static void R_Shadow_FreeDeferred(void);
602 static void r_shadow_shutdown(void)
605 R_Shadow_UncompileWorldLights();
607 R_Shadow_FreeShadowMaps();
609 r_shadow_usingdeferredprepass = false;
610 if (r_shadow_prepass_width)
611 R_Shadow_FreeDeferred();
612 r_shadow_prepass_width = r_shadow_prepass_height = 0;
615 r_shadow_bouncegridtexture = NULL;
616 r_shadow_bouncegridpixels = NULL;
617 r_shadow_bouncegridhighpixels = NULL;
618 r_shadow_bouncegridnumpixels = 0;
619 r_shadow_bouncegriddirectional = false;
620 r_shadow_attenuationgradienttexture = NULL;
621 r_shadow_attenuation2dtexture = NULL;
622 r_shadow_attenuation3dtexture = NULL;
623 R_FreeTexturePool(&r_shadow_texturepool);
624 R_FreeTexturePool(&r_shadow_filters_texturepool);
625 maxshadowtriangles = 0;
627 Mem_Free(shadowelements);
628 shadowelements = NULL;
630 Mem_Free(shadowvertex3f);
631 shadowvertex3f = NULL;
634 Mem_Free(vertexupdate);
637 Mem_Free(vertexremap);
643 Mem_Free(shadowmark);
646 Mem_Free(shadowmarklist);
647 shadowmarklist = NULL;
652 Mem_Free(shadowsides);
655 Mem_Free(shadowsideslist);
656 shadowsideslist = NULL;
657 r_shadow_buffer_numleafpvsbytes = 0;
658 if (r_shadow_buffer_visitingleafpvs)
659 Mem_Free(r_shadow_buffer_visitingleafpvs);
660 r_shadow_buffer_visitingleafpvs = NULL;
661 if (r_shadow_buffer_leafpvs)
662 Mem_Free(r_shadow_buffer_leafpvs);
663 r_shadow_buffer_leafpvs = NULL;
664 if (r_shadow_buffer_leaflist)
665 Mem_Free(r_shadow_buffer_leaflist);
666 r_shadow_buffer_leaflist = NULL;
667 r_shadow_buffer_numsurfacepvsbytes = 0;
668 if (r_shadow_buffer_surfacepvs)
669 Mem_Free(r_shadow_buffer_surfacepvs);
670 r_shadow_buffer_surfacepvs = NULL;
671 if (r_shadow_buffer_surfacelist)
672 Mem_Free(r_shadow_buffer_surfacelist);
673 r_shadow_buffer_surfacelist = NULL;
674 if (r_shadow_buffer_surfacesides)
675 Mem_Free(r_shadow_buffer_surfacesides);
676 r_shadow_buffer_surfacesides = NULL;
677 r_shadow_buffer_numshadowtrispvsbytes = 0;
678 if (r_shadow_buffer_shadowtrispvs)
679 Mem_Free(r_shadow_buffer_shadowtrispvs);
680 r_shadow_buffer_numlighttrispvsbytes = 0;
681 if (r_shadow_buffer_lighttrispvs)
682 Mem_Free(r_shadow_buffer_lighttrispvs);
685 static void r_shadow_newmap(void)
687 if (r_shadow_bouncegridtexture) R_FreeTexture(r_shadow_bouncegridtexture);r_shadow_bouncegridtexture = NULL;
688 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
689 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
690 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
691 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
692 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
693 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
694 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
695 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
696 R_Shadow_EditLights_Reload_f();
699 void R_Shadow_Init(void)
701 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
702 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
703 Cvar_RegisterVariable(&r_shadow_usebihculling);
704 Cvar_RegisterVariable(&r_shadow_usenormalmap);
705 Cvar_RegisterVariable(&r_shadow_debuglight);
706 Cvar_RegisterVariable(&r_shadow_deferred);
707 Cvar_RegisterVariable(&r_shadow_gloss);
708 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
709 Cvar_RegisterVariable(&r_shadow_glossintensity);
710 Cvar_RegisterVariable(&r_shadow_glossexponent);
711 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
712 Cvar_RegisterVariable(&r_shadow_glossexact);
713 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
714 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
715 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
716 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
717 Cvar_RegisterVariable(&r_shadow_projectdistance);
718 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
719 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
720 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
721 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
722 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
723 Cvar_RegisterVariable(&r_shadow_realtime_world);
724 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
725 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
726 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
727 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
728 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
729 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
730 Cvar_RegisterVariable(&r_shadow_scissor);
731 Cvar_RegisterVariable(&r_shadow_shadowmapping);
732 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
733 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
734 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
735 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
736 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
737 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
738 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
739 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
740 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
741 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
742 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
743 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
744 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
745 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
746 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
747 Cvar_RegisterVariable(&r_shadow_polygonfactor);
748 Cvar_RegisterVariable(&r_shadow_polygonoffset);
749 Cvar_RegisterVariable(&r_shadow_texture3d);
750 Cvar_RegisterVariable(&r_shadow_bouncegrid);
751 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
752 Cvar_RegisterVariable(&r_shadow_bouncegrid_directionalshading);
753 Cvar_RegisterVariable(&r_shadow_bouncegrid_dlightparticlemultiplier);
754 Cvar_RegisterVariable(&r_shadow_bouncegrid_hitmodels);
755 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
756 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
757 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightradiusscale);
758 Cvar_RegisterVariable(&r_shadow_bouncegrid_maxbounce);
759 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
760 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
761 Cvar_RegisterVariable(&r_shadow_bouncegrid_photons);
762 Cvar_RegisterVariable(&r_shadow_bouncegrid_spacing);
763 Cvar_RegisterVariable(&r_shadow_bouncegrid_stablerandom);
764 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
765 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
766 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
767 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
768 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_photons);
769 Cvar_RegisterVariable(&r_shadow_bouncegrid_updateinterval);
770 Cvar_RegisterVariable(&r_shadow_bouncegrid_x);
771 Cvar_RegisterVariable(&r_shadow_bouncegrid_y);
772 Cvar_RegisterVariable(&r_shadow_bouncegrid_z);
773 Cvar_RegisterVariable(&r_coronas);
774 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
775 Cvar_RegisterVariable(&r_coronas_occlusionquery);
776 Cvar_RegisterVariable(&gl_flashblend);
777 Cvar_RegisterVariable(&gl_ext_separatestencil);
778 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
779 R_Shadow_EditLights_Init();
780 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
781 maxshadowtriangles = 0;
782 shadowelements = NULL;
783 maxshadowvertices = 0;
784 shadowvertex3f = NULL;
792 shadowmarklist = NULL;
797 shadowsideslist = NULL;
798 r_shadow_buffer_numleafpvsbytes = 0;
799 r_shadow_buffer_visitingleafpvs = NULL;
800 r_shadow_buffer_leafpvs = NULL;
801 r_shadow_buffer_leaflist = NULL;
802 r_shadow_buffer_numsurfacepvsbytes = 0;
803 r_shadow_buffer_surfacepvs = NULL;
804 r_shadow_buffer_surfacelist = NULL;
805 r_shadow_buffer_surfacesides = NULL;
806 r_shadow_buffer_shadowtrispvs = NULL;
807 r_shadow_buffer_lighttrispvs = NULL;
808 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
811 matrix4x4_t matrix_attenuationxyz =
814 {0.5, 0.0, 0.0, 0.5},
815 {0.0, 0.5, 0.0, 0.5},
816 {0.0, 0.0, 0.5, 0.5},
821 matrix4x4_t matrix_attenuationz =
824 {0.0, 0.0, 0.5, 0.5},
825 {0.0, 0.0, 0.0, 0.5},
826 {0.0, 0.0, 0.0, 0.5},
831 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
833 numvertices = ((numvertices + 255) & ~255) * vertscale;
834 numtriangles = ((numtriangles + 255) & ~255) * triscale;
835 // make sure shadowelements is big enough for this volume
836 if (maxshadowtriangles < numtriangles)
838 maxshadowtriangles = numtriangles;
840 Mem_Free(shadowelements);
841 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
843 // make sure shadowvertex3f is big enough for this volume
844 if (maxshadowvertices < numvertices)
846 maxshadowvertices = numvertices;
848 Mem_Free(shadowvertex3f);
849 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
853 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
855 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
856 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
857 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
858 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
859 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
861 if (r_shadow_buffer_visitingleafpvs)
862 Mem_Free(r_shadow_buffer_visitingleafpvs);
863 if (r_shadow_buffer_leafpvs)
864 Mem_Free(r_shadow_buffer_leafpvs);
865 if (r_shadow_buffer_leaflist)
866 Mem_Free(r_shadow_buffer_leaflist);
867 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
868 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
869 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
870 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
872 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
874 if (r_shadow_buffer_surfacepvs)
875 Mem_Free(r_shadow_buffer_surfacepvs);
876 if (r_shadow_buffer_surfacelist)
877 Mem_Free(r_shadow_buffer_surfacelist);
878 if (r_shadow_buffer_surfacesides)
879 Mem_Free(r_shadow_buffer_surfacesides);
880 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
881 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
882 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
883 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
885 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
887 if (r_shadow_buffer_shadowtrispvs)
888 Mem_Free(r_shadow_buffer_shadowtrispvs);
889 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
890 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
892 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
894 if (r_shadow_buffer_lighttrispvs)
895 Mem_Free(r_shadow_buffer_lighttrispvs);
896 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
897 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
901 void R_Shadow_PrepareShadowMark(int numtris)
903 // make sure shadowmark is big enough for this volume
904 if (maxshadowmark < numtris)
906 maxshadowmark = numtris;
908 Mem_Free(shadowmark);
910 Mem_Free(shadowmarklist);
911 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
912 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
916 // if shadowmarkcount wrapped we clear the array and adjust accordingly
917 if (shadowmarkcount == 0)
920 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
925 void R_Shadow_PrepareShadowSides(int numtris)
927 if (maxshadowsides < numtris)
929 maxshadowsides = numtris;
931 Mem_Free(shadowsides);
933 Mem_Free(shadowsideslist);
934 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
935 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
940 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)
943 int outtriangles = 0, outvertices = 0;
946 float ratio, direction[3], projectvector[3];
948 if (projectdirection)
949 VectorScale(projectdirection, projectdistance, projectvector);
951 VectorClear(projectvector);
953 // create the vertices
954 if (projectdirection)
956 for (i = 0;i < numshadowmarktris;i++)
958 element = inelement3i + shadowmarktris[i] * 3;
959 for (j = 0;j < 3;j++)
961 if (vertexupdate[element[j]] != vertexupdatenum)
963 vertexupdate[element[j]] = vertexupdatenum;
964 vertexremap[element[j]] = outvertices;
965 vertex = invertex3f + element[j] * 3;
966 // project one copy of the vertex according to projectvector
967 VectorCopy(vertex, outvertex3f);
968 VectorAdd(vertex, projectvector, (outvertex3f + 3));
977 for (i = 0;i < numshadowmarktris;i++)
979 element = inelement3i + shadowmarktris[i] * 3;
980 for (j = 0;j < 3;j++)
982 if (vertexupdate[element[j]] != vertexupdatenum)
984 vertexupdate[element[j]] = vertexupdatenum;
985 vertexremap[element[j]] = outvertices;
986 vertex = invertex3f + element[j] * 3;
987 // project one copy of the vertex to the sphere radius of the light
988 // (FIXME: would projecting it to the light box be better?)
989 VectorSubtract(vertex, projectorigin, direction);
990 ratio = projectdistance / VectorLength(direction);
991 VectorCopy(vertex, outvertex3f);
992 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1000 if (r_shadow_frontsidecasting.integer)
1002 for (i = 0;i < numshadowmarktris;i++)
1004 int remappedelement[3];
1006 const int *neighbortriangle;
1008 markindex = shadowmarktris[i] * 3;
1009 element = inelement3i + markindex;
1010 neighbortriangle = inneighbor3i + markindex;
1011 // output the front and back triangles
1012 outelement3i[0] = vertexremap[element[0]];
1013 outelement3i[1] = vertexremap[element[1]];
1014 outelement3i[2] = vertexremap[element[2]];
1015 outelement3i[3] = vertexremap[element[2]] + 1;
1016 outelement3i[4] = vertexremap[element[1]] + 1;
1017 outelement3i[5] = vertexremap[element[0]] + 1;
1021 // output the sides (facing outward from this triangle)
1022 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1024 remappedelement[0] = vertexremap[element[0]];
1025 remappedelement[1] = vertexremap[element[1]];
1026 outelement3i[0] = remappedelement[1];
1027 outelement3i[1] = remappedelement[0];
1028 outelement3i[2] = remappedelement[0] + 1;
1029 outelement3i[3] = remappedelement[1];
1030 outelement3i[4] = remappedelement[0] + 1;
1031 outelement3i[5] = remappedelement[1] + 1;
1036 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1038 remappedelement[1] = vertexremap[element[1]];
1039 remappedelement[2] = vertexremap[element[2]];
1040 outelement3i[0] = remappedelement[2];
1041 outelement3i[1] = remappedelement[1];
1042 outelement3i[2] = remappedelement[1] + 1;
1043 outelement3i[3] = remappedelement[2];
1044 outelement3i[4] = remappedelement[1] + 1;
1045 outelement3i[5] = remappedelement[2] + 1;
1050 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1052 remappedelement[0] = vertexremap[element[0]];
1053 remappedelement[2] = vertexremap[element[2]];
1054 outelement3i[0] = remappedelement[0];
1055 outelement3i[1] = remappedelement[2];
1056 outelement3i[2] = remappedelement[2] + 1;
1057 outelement3i[3] = remappedelement[0];
1058 outelement3i[4] = remappedelement[2] + 1;
1059 outelement3i[5] = remappedelement[0] + 1;
1068 for (i = 0;i < numshadowmarktris;i++)
1070 int remappedelement[3];
1072 const int *neighbortriangle;
1074 markindex = shadowmarktris[i] * 3;
1075 element = inelement3i + markindex;
1076 neighbortriangle = inneighbor3i + markindex;
1077 // output the front and back triangles
1078 outelement3i[0] = vertexremap[element[2]];
1079 outelement3i[1] = vertexremap[element[1]];
1080 outelement3i[2] = vertexremap[element[0]];
1081 outelement3i[3] = vertexremap[element[0]] + 1;
1082 outelement3i[4] = vertexremap[element[1]] + 1;
1083 outelement3i[5] = vertexremap[element[2]] + 1;
1087 // output the sides (facing outward from this triangle)
1088 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1090 remappedelement[0] = vertexremap[element[0]];
1091 remappedelement[1] = vertexremap[element[1]];
1092 outelement3i[0] = remappedelement[0];
1093 outelement3i[1] = remappedelement[1];
1094 outelement3i[2] = remappedelement[1] + 1;
1095 outelement3i[3] = remappedelement[0];
1096 outelement3i[4] = remappedelement[1] + 1;
1097 outelement3i[5] = remappedelement[0] + 1;
1102 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1104 remappedelement[1] = vertexremap[element[1]];
1105 remappedelement[2] = vertexremap[element[2]];
1106 outelement3i[0] = remappedelement[1];
1107 outelement3i[1] = remappedelement[2];
1108 outelement3i[2] = remappedelement[2] + 1;
1109 outelement3i[3] = remappedelement[1];
1110 outelement3i[4] = remappedelement[2] + 1;
1111 outelement3i[5] = remappedelement[1] + 1;
1116 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1118 remappedelement[0] = vertexremap[element[0]];
1119 remappedelement[2] = vertexremap[element[2]];
1120 outelement3i[0] = remappedelement[2];
1121 outelement3i[1] = remappedelement[0];
1122 outelement3i[2] = remappedelement[0] + 1;
1123 outelement3i[3] = remappedelement[2];
1124 outelement3i[4] = remappedelement[0] + 1;
1125 outelement3i[5] = remappedelement[2] + 1;
1133 *outnumvertices = outvertices;
1134 return outtriangles;
1137 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)
1140 int outtriangles = 0, outvertices = 0;
1142 const float *vertex;
1143 float ratio, direction[3], projectvector[3];
1146 if (projectdirection)
1147 VectorScale(projectdirection, projectdistance, projectvector);
1149 VectorClear(projectvector);
1151 for (i = 0;i < numshadowmarktris;i++)
1153 int remappedelement[3];
1155 const int *neighbortriangle;
1157 markindex = shadowmarktris[i] * 3;
1158 neighbortriangle = inneighbor3i + markindex;
1159 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1160 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1161 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1162 if (side[0] + side[1] + side[2] == 0)
1166 element = inelement3i + markindex;
1168 // create the vertices
1169 for (j = 0;j < 3;j++)
1171 if (side[j] + side[j+1] == 0)
1174 if (vertexupdate[k] != vertexupdatenum)
1176 vertexupdate[k] = vertexupdatenum;
1177 vertexremap[k] = outvertices;
1178 vertex = invertex3f + k * 3;
1179 VectorCopy(vertex, outvertex3f);
1180 if (projectdirection)
1182 // project one copy of the vertex according to projectvector
1183 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1187 // project one copy of the vertex to the sphere radius of the light
1188 // (FIXME: would projecting it to the light box be better?)
1189 VectorSubtract(vertex, projectorigin, direction);
1190 ratio = projectdistance / VectorLength(direction);
1191 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1198 // output the sides (facing outward from this triangle)
1201 remappedelement[0] = vertexremap[element[0]];
1202 remappedelement[1] = vertexremap[element[1]];
1203 outelement3i[0] = remappedelement[1];
1204 outelement3i[1] = remappedelement[0];
1205 outelement3i[2] = remappedelement[0] + 1;
1206 outelement3i[3] = remappedelement[1];
1207 outelement3i[4] = remappedelement[0] + 1;
1208 outelement3i[5] = remappedelement[1] + 1;
1215 remappedelement[1] = vertexremap[element[1]];
1216 remappedelement[2] = vertexremap[element[2]];
1217 outelement3i[0] = remappedelement[2];
1218 outelement3i[1] = remappedelement[1];
1219 outelement3i[2] = remappedelement[1] + 1;
1220 outelement3i[3] = remappedelement[2];
1221 outelement3i[4] = remappedelement[1] + 1;
1222 outelement3i[5] = remappedelement[2] + 1;
1229 remappedelement[0] = vertexremap[element[0]];
1230 remappedelement[2] = vertexremap[element[2]];
1231 outelement3i[0] = remappedelement[0];
1232 outelement3i[1] = remappedelement[2];
1233 outelement3i[2] = remappedelement[2] + 1;
1234 outelement3i[3] = remappedelement[0];
1235 outelement3i[4] = remappedelement[2] + 1;
1236 outelement3i[5] = remappedelement[0] + 1;
1243 *outnumvertices = outvertices;
1244 return outtriangles;
1247 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)
1253 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1255 tend = firsttriangle + numtris;
1256 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1258 // surface box entirely inside light box, no box cull
1259 if (projectdirection)
1261 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1263 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1264 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1265 shadowmarklist[numshadowmark++] = t;
1270 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1271 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1272 shadowmarklist[numshadowmark++] = t;
1277 // surface box not entirely inside light box, cull each triangle
1278 if (projectdirection)
1280 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1282 v[0] = invertex3f + e[0] * 3;
1283 v[1] = invertex3f + e[1] * 3;
1284 v[2] = invertex3f + e[2] * 3;
1285 TriangleNormal(v[0], v[1], v[2], normal);
1286 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1287 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1288 shadowmarklist[numshadowmark++] = t;
1293 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1295 v[0] = invertex3f + e[0] * 3;
1296 v[1] = invertex3f + e[1] * 3;
1297 v[2] = invertex3f + e[2] * 3;
1298 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1299 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1300 shadowmarklist[numshadowmark++] = t;
1306 static qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1311 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1313 // check if the shadow volume intersects the near plane
1315 // a ray between the eye and light origin may intersect the caster,
1316 // indicating that the shadow may touch the eye location, however we must
1317 // test the near plane (a polygon), not merely the eye location, so it is
1318 // easiest to enlarge the caster bounding shape slightly for this.
1324 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)
1326 int i, tris, outverts;
1327 if (projectdistance < 0.1)
1329 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1332 if (!numverts || !nummarktris)
1334 // make sure shadowelements is big enough for this volume
1335 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1336 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1338 if (maxvertexupdate < numverts)
1340 maxvertexupdate = numverts;
1342 Mem_Free(vertexupdate);
1344 Mem_Free(vertexremap);
1345 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1346 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1347 vertexupdatenum = 0;
1350 if (vertexupdatenum == 0)
1352 vertexupdatenum = 1;
1353 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1354 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1357 for (i = 0;i < nummarktris;i++)
1358 shadowmark[marktris[i]] = shadowmarkcount;
1360 if (r_shadow_compilingrtlight)
1362 // if we're compiling an rtlight, capture the mesh
1363 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1364 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1365 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1366 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1368 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1370 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1371 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1372 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1376 // decide which type of shadow to generate and set stencil mode
1377 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1378 // generate the sides or a solid volume, depending on type
1379 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1380 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1382 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1383 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1384 r_refdef.stats.lights_shadowtriangles += tris;
1385 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1387 // increment stencil if frontface is infront of depthbuffer
1388 GL_CullFace(r_refdef.view.cullface_front);
1389 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1390 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1391 // decrement stencil if backface is infront of depthbuffer
1392 GL_CullFace(r_refdef.view.cullface_back);
1393 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1395 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1397 // decrement stencil if backface is behind depthbuffer
1398 GL_CullFace(r_refdef.view.cullface_front);
1399 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1400 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1401 // increment stencil if frontface is behind depthbuffer
1402 GL_CullFace(r_refdef.view.cullface_back);
1403 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1405 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1406 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1410 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1412 // p1, p2, p3 are in the cubemap's local coordinate system
1413 // bias = border/(size - border)
1416 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1417 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1418 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1419 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1421 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1422 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1423 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1424 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1426 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1427 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1428 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1430 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1431 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1432 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1433 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1435 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1436 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1437 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1438 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1440 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1441 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1442 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1444 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1445 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1446 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1447 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1449 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1450 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1451 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1452 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1454 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1455 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1456 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1461 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1463 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1464 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1467 VectorSubtract(maxs, mins, radius);
1468 VectorScale(radius, 0.5f, radius);
1469 VectorAdd(mins, radius, center);
1470 Matrix4x4_Transform(worldtolight, center, lightcenter);
1471 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1472 VectorSubtract(lightcenter, lightradius, pmin);
1473 VectorAdd(lightcenter, lightradius, pmax);
1475 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1476 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1477 if(ap1 > bias*an1 && ap2 > bias*an2)
1479 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1480 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1481 if(an1 > bias*ap1 && an2 > bias*ap2)
1483 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1484 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1486 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1487 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1488 if(ap1 > bias*an1 && ap2 > bias*an2)
1490 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1491 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1492 if(an1 > bias*ap1 && an2 > bias*ap2)
1494 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1495 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1497 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1498 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1499 if(ap1 > bias*an1 && ap2 > bias*an2)
1501 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1502 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1503 if(an1 > bias*ap1 && an2 > bias*ap2)
1505 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1506 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1511 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1513 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1515 // p is in the cubemap's local coordinate system
1516 // bias = border/(size - border)
1517 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1518 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1519 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1521 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1522 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1523 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1524 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1525 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1526 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1530 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1534 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1535 float scale = (size - 2*border)/size, len;
1536 float bias = border / (float)(size - border), dp, dn, ap, an;
1537 // check if cone enclosing side would cross frustum plane
1538 scale = 2 / (scale*scale + 2);
1539 for (i = 0;i < 5;i++)
1541 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1543 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1544 len = scale*VectorLength2(n);
1545 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1546 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1547 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1549 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1551 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1552 len = scale*VectorLength(n);
1553 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1554 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1555 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1557 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1558 // check if frustum corners/origin cross plane sides
1560 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1561 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1562 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1563 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1564 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1565 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1566 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1567 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1568 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1569 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1570 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1571 for (i = 0;i < 4;i++)
1573 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1574 VectorSubtract(n, p, n);
1575 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1576 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1577 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1578 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1579 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1580 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1581 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1582 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1583 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1586 // finite version, assumes corners are a finite distance from origin dependent on far plane
1587 for (i = 0;i < 5;i++)
1589 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1590 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1591 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1592 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1593 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1594 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1595 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1596 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1597 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1598 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1601 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1604 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)
1612 int mask, surfacemask = 0;
1613 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1615 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1616 tend = firsttriangle + numtris;
1617 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1619 // surface box entirely inside light box, no box cull
1620 if (projectdirection)
1622 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1624 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1625 TriangleNormal(v[0], v[1], v[2], normal);
1626 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1628 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1629 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1630 surfacemask |= mask;
1633 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;
1634 shadowsides[numshadowsides] = mask;
1635 shadowsideslist[numshadowsides++] = t;
1642 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1644 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1645 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1647 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1648 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1649 surfacemask |= mask;
1652 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;
1653 shadowsides[numshadowsides] = mask;
1654 shadowsideslist[numshadowsides++] = t;
1662 // surface box not entirely inside light box, cull each triangle
1663 if (projectdirection)
1665 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1667 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1668 TriangleNormal(v[0], v[1], v[2], normal);
1669 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1670 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1672 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1673 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1674 surfacemask |= mask;
1677 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;
1678 shadowsides[numshadowsides] = mask;
1679 shadowsideslist[numshadowsides++] = t;
1686 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1688 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1689 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1690 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1692 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1693 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1694 surfacemask |= mask;
1697 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1698 shadowsides[numshadowsides] = mask;
1699 shadowsideslist[numshadowsides++] = t;
1708 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)
1710 int i, j, outtriangles = 0;
1711 int *outelement3i[6];
1712 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1714 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1715 // make sure shadowelements is big enough for this mesh
1716 if (maxshadowtriangles < outtriangles)
1717 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1719 // compute the offset and size of the separate index lists for each cubemap side
1721 for (i = 0;i < 6;i++)
1723 outelement3i[i] = shadowelements + outtriangles * 3;
1724 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1725 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1726 outtriangles += sidetotals[i];
1729 // gather up the (sparse) triangles into separate index lists for each cubemap side
1730 for (i = 0;i < numsidetris;i++)
1732 const int *element = elements + sidetris[i] * 3;
1733 for (j = 0;j < 6;j++)
1735 if (sides[i] & (1 << j))
1737 outelement3i[j][0] = element[0];
1738 outelement3i[j][1] = element[1];
1739 outelement3i[j][2] = element[2];
1740 outelement3i[j] += 3;
1745 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1748 static void R_Shadow_MakeTextures_MakeCorona(void)
1752 unsigned char pixels[32][32][4];
1753 for (y = 0;y < 32;y++)
1755 dy = (y - 15.5f) * (1.0f / 16.0f);
1756 for (x = 0;x < 32;x++)
1758 dx = (x - 15.5f) * (1.0f / 16.0f);
1759 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1760 a = bound(0, a, 255);
1761 pixels[y][x][0] = a;
1762 pixels[y][x][1] = a;
1763 pixels[y][x][2] = a;
1764 pixels[y][x][3] = 255;
1767 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, false);
1770 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1772 float dist = sqrt(x*x+y*y+z*z);
1773 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1774 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1775 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1778 static void R_Shadow_MakeTextures(void)
1781 float intensity, dist;
1783 R_Shadow_FreeShadowMaps();
1784 R_FreeTexturePool(&r_shadow_texturepool);
1785 r_shadow_texturepool = R_AllocTexturePool();
1786 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1787 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1788 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1789 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1790 for (x = 0;x <= ATTENTABLESIZE;x++)
1792 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1793 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1794 r_shadow_attentable[x] = bound(0, intensity, 1);
1796 // 1D gradient texture
1797 for (x = 0;x < ATTEN1DSIZE;x++)
1798 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1799 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1800 // 2D circle texture
1801 for (y = 0;y < ATTEN2DSIZE;y++)
1802 for (x = 0;x < ATTEN2DSIZE;x++)
1803 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);
1804 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1805 // 3D sphere texture
1806 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1808 for (z = 0;z < ATTEN3DSIZE;z++)
1809 for (y = 0;y < ATTEN3DSIZE;y++)
1810 for (x = 0;x < ATTEN3DSIZE;x++)
1811 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));
1812 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);
1815 r_shadow_attenuation3dtexture = NULL;
1818 R_Shadow_MakeTextures_MakeCorona();
1820 // Editor light sprites
1821 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1838 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1839 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1856 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1857 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1874 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1875 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1892 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1893 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1910 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1911 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1928 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1931 void R_Shadow_ValidateCvars(void)
1933 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1934 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1935 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1936 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1937 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1938 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1941 void R_Shadow_RenderMode_Begin(void)
1947 R_Shadow_ValidateCvars();
1949 if (!r_shadow_attenuation2dtexture
1950 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1951 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1952 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1953 R_Shadow_MakeTextures();
1956 R_Mesh_ResetTextureState();
1957 GL_BlendFunc(GL_ONE, GL_ZERO);
1958 GL_DepthRange(0, 1);
1959 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1961 GL_DepthMask(false);
1962 GL_Color(0, 0, 0, 1);
1963 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1965 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1967 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1969 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1970 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1972 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1974 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1975 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1979 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1980 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1983 switch(vid.renderpath)
1985 case RENDERPATH_GL20:
1986 case RENDERPATH_D3D9:
1987 case RENDERPATH_D3D10:
1988 case RENDERPATH_D3D11:
1989 case RENDERPATH_SOFT:
1990 case RENDERPATH_GLES2:
1991 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1993 case RENDERPATH_GL11:
1994 case RENDERPATH_GL13:
1995 case RENDERPATH_GLES1:
1996 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1997 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1998 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1999 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
2000 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
2001 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
2003 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
2009 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
2010 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
2011 r_shadow_drawbuffer = drawbuffer;
2012 r_shadow_readbuffer = readbuffer;
2014 r_shadow_cullface_front = r_refdef.view.cullface_front;
2015 r_shadow_cullface_back = r_refdef.view.cullface_back;
2018 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
2020 rsurface.rtlight = rtlight;
2023 void R_Shadow_RenderMode_Reset(void)
2025 R_Mesh_ResetTextureState();
2026 R_Mesh_SetRenderTargets(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture, NULL, NULL, NULL);
2027 R_SetViewport(&r_refdef.view.viewport);
2028 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
2029 GL_DepthRange(0, 1);
2031 GL_DepthMask(false);
2032 GL_DepthFunc(GL_LEQUAL);
2033 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2034 r_refdef.view.cullface_front = r_shadow_cullface_front;
2035 r_refdef.view.cullface_back = r_shadow_cullface_back;
2036 GL_CullFace(r_refdef.view.cullface_back);
2037 GL_Color(1, 1, 1, 1);
2038 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2039 GL_BlendFunc(GL_ONE, GL_ZERO);
2040 R_SetupShader_Generic_NoTexture(false, false);
2041 r_shadow_usingshadowmap2d = false;
2042 r_shadow_usingshadowmaportho = false;
2043 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2046 void R_Shadow_ClearStencil(void)
2048 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2049 r_refdef.stats.lights_clears++;
2052 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2054 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2055 if (r_shadow_rendermode == mode)
2057 R_Shadow_RenderMode_Reset();
2058 GL_DepthFunc(GL_LESS);
2059 GL_ColorMask(0, 0, 0, 0);
2060 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2061 GL_CullFace(GL_NONE);
2062 R_SetupShader_DepthOrShadow(false, false);
2063 r_shadow_rendermode = mode;
2068 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2069 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2070 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2072 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2073 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2074 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2079 static void R_Shadow_MakeVSDCT(void)
2081 // maps to a 2x3 texture rectangle with normalized coordinates
2086 // stores abs(dir.xy), offset.xy/2.5
2087 unsigned char data[4*6] =
2089 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2090 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2091 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2092 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2093 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2094 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2096 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2099 static void R_Shadow_MakeShadowMap(int side, int size)
2101 switch (r_shadow_shadowmode)
2103 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2104 if (r_shadow_shadowmap2ddepthtexture) return;
2105 if (r_fb.usedepthtextures)
2107 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);
2108 r_shadow_shadowmap2ddepthbuffer = NULL;
2109 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2113 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);
2114 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);
2115 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2123 static void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2125 float nearclip, farclip, bias;
2126 r_viewport_t viewport;
2129 float clearcolor[4];
2130 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2132 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2133 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2134 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2135 r_shadow_shadowmapside = side;
2136 r_shadow_shadowmapsize = size;
2138 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2139 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2140 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2141 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2143 // complex unrolled cube approach (more flexible)
2144 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2145 R_Shadow_MakeVSDCT();
2146 if (!r_shadow_shadowmap2ddepthtexture)
2147 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2148 fbo2d = r_shadow_fbo2d;
2149 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
2150 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
2151 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2153 R_Mesh_ResetTextureState();
2154 R_Shadow_RenderMode_Reset();
2155 if (r_shadow_shadowmap2ddepthbuffer)
2156 R_Mesh_SetRenderTargets(fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2158 R_Mesh_SetRenderTargets(fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2159 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL);
2160 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2165 R_SetViewport(&viewport);
2166 flipped = (side & 1) ^ (side >> 2);
2167 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2168 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2169 if (r_shadow_shadowmap2ddepthbuffer)
2171 // completely different meaning than in depthtexture approach
2172 r_shadow_shadowmap_parameters[1] = 0;
2173 r_shadow_shadowmap_parameters[3] = -bias;
2175 Vector4Set(clearcolor, 1,1,1,1);
2176 if (r_shadow_shadowmap2ddepthbuffer)
2177 GL_ColorMask(1,1,1,1);
2179 GL_ColorMask(0,0,0,0);
2180 switch(vid.renderpath)
2182 case RENDERPATH_GL11:
2183 case RENDERPATH_GL13:
2184 case RENDERPATH_GL20:
2185 case RENDERPATH_SOFT:
2186 case RENDERPATH_GLES1:
2187 case RENDERPATH_GLES2:
2188 GL_CullFace(r_refdef.view.cullface_back);
2189 // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
2190 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2192 // get tightest scissor rectangle that encloses all viewports in the clear mask
2193 int x1 = clear & 0x15 ? 0 : size;
2194 int x2 = clear & 0x2A ? 2 * size : size;
2195 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2196 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2197 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2200 if (r_shadow_shadowmap2ddepthbuffer)
2201 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2203 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2206 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2208 case RENDERPATH_D3D9:
2209 case RENDERPATH_D3D10:
2210 case RENDERPATH_D3D11:
2211 // we invert the cull mode because we flip the projection matrix
2212 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2213 GL_CullFace(r_refdef.view.cullface_front);
2214 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2215 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2218 if (r_shadow_shadowmap2ddepthbuffer)
2219 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2221 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2227 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2229 R_Mesh_ResetTextureState();
2232 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2233 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2234 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2235 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2237 R_Shadow_RenderMode_Reset();
2238 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2240 GL_DepthFunc(GL_EQUAL);
2241 // do global setup needed for the chosen lighting mode
2242 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2243 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2244 r_shadow_usingshadowmap2d = shadowmapping;
2245 r_shadow_rendermode = r_shadow_lightingrendermode;
2246 // only draw light where this geometry was already rendered AND the
2247 // stencil is 128 (values other than this mean shadow)
2249 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2251 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2254 static const unsigned short bboxelements[36] =
2264 static const float bboxpoints[8][3] =
2276 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2279 float vertex3f[8*3];
2280 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2281 // do global setup needed for the chosen lighting mode
2282 R_Shadow_RenderMode_Reset();
2283 r_shadow_rendermode = r_shadow_lightingrendermode;
2284 R_EntityMatrix(&identitymatrix);
2285 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2286 // only draw light where this geometry was already rendered AND the
2287 // stencil is 128 (values other than this mean shadow)
2288 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2289 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
2290 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2292 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
2294 r_shadow_usingshadowmap2d = shadowmapping;
2296 // render the lighting
2297 R_SetupShader_DeferredLight(rsurface.rtlight);
2298 for (i = 0;i < 8;i++)
2299 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2300 GL_ColorMask(1,1,1,1);
2301 GL_DepthMask(false);
2302 GL_DepthRange(0, 1);
2303 GL_PolygonOffset(0, 0);
2305 GL_DepthFunc(GL_GREATER);
2306 GL_CullFace(r_refdef.view.cullface_back);
2307 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL);
2308 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2311 void R_Shadow_UpdateBounceGridTexture(void)
2313 #define MAXBOUNCEGRIDPARTICLESPERLIGHT 1048576
2315 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2317 int hitsupercontentsmask;
2326 //trace_t cliptrace2;
2327 //trace_t cliptrace3;
2328 unsigned char *pixel;
2329 unsigned char *pixels;
2332 unsigned int lightindex;
2334 unsigned int range1;
2335 unsigned int range2;
2336 unsigned int seed = (unsigned int)(realtime * 1000.0f);
2338 vec3_t baseshotcolor;
2351 vec3_t cullmins, cullmaxs;
2354 vec_t lightintensity;
2355 vec_t photonscaling;
2356 vec_t photonresidual;
2358 float texlerp[2][3];
2359 float splatcolor[32];
2360 float pixelweight[8];
2372 r_shadow_bouncegrid_settings_t settings;
2373 qboolean enable = r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
2374 qboolean allowdirectionalshading = false;
2375 switch(vid.renderpath)
2377 case RENDERPATH_GL20:
2378 allowdirectionalshading = true;
2379 if (!vid.support.ext_texture_3d)
2382 case RENDERPATH_GLES2:
2383 // for performance reasons, do not use directional shading on GLES devices
2384 if (!vid.support.ext_texture_3d)
2387 // these renderpaths do not currently have the code to display the bouncegrid, so disable it on them...
2388 case RENDERPATH_GL11:
2389 case RENDERPATH_GL13:
2390 case RENDERPATH_GLES1:
2391 case RENDERPATH_SOFT:
2392 case RENDERPATH_D3D9:
2393 case RENDERPATH_D3D10:
2394 case RENDERPATH_D3D11:
2398 r_shadow_bouncegridintensity = r_shadow_bouncegrid_intensity.value;
2400 // see if there are really any lights to render...
2401 if (enable && r_shadow_bouncegrid_static.integer)
2404 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2405 for (lightindex = 0;lightindex < range;lightindex++)
2407 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2408 if (!light || !(light->flags & flag))
2410 rtlight = &light->rtlight;
2411 // when static, we skip styled lights because they tend to change...
2412 if (rtlight->style > 0)
2414 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
2415 if (!VectorLength2(lightcolor))
2424 if (r_shadow_bouncegridtexture)
2426 R_FreeTexture(r_shadow_bouncegridtexture);
2427 r_shadow_bouncegridtexture = NULL;
2429 if (r_shadow_bouncegridpixels)
2430 Mem_Free(r_shadow_bouncegridpixels);
2431 r_shadow_bouncegridpixels = NULL;
2432 if (r_shadow_bouncegridhighpixels)
2433 Mem_Free(r_shadow_bouncegridhighpixels);
2434 r_shadow_bouncegridhighpixels = NULL;
2435 r_shadow_bouncegridnumpixels = 0;
2436 r_shadow_bouncegriddirectional = false;
2440 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
2441 memset(&settings, 0, sizeof(settings));
2442 settings.staticmode = r_shadow_bouncegrid_static.integer != 0;
2443 settings.bounceanglediffuse = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
2444 settings.directionalshading = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_directionalshading.integer != 0) && allowdirectionalshading;
2445 settings.dlightparticlemultiplier = r_shadow_bouncegrid_dlightparticlemultiplier.value;
2446 settings.hitmodels = r_shadow_bouncegrid_hitmodels.integer != 0;
2447 settings.includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
2448 settings.lightradiusscale = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_lightradiusscale.value);
2449 settings.maxbounce = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_maxbounce.integer);
2450 settings.particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
2451 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);
2452 settings.photons = r_shadow_bouncegrid_static.integer ? r_shadow_bouncegrid_static_photons.integer : r_shadow_bouncegrid_photons.integer;
2453 settings.spacing[0] = r_shadow_bouncegrid_spacing.value;
2454 settings.spacing[1] = r_shadow_bouncegrid_spacing.value;
2455 settings.spacing[2] = r_shadow_bouncegrid_spacing.value;
2456 settings.stablerandom = r_shadow_bouncegrid_stablerandom.integer;
2458 // bound the values for sanity
2459 settings.photons = bound(1, settings.photons, 1048576);
2460 settings.lightradiusscale = bound(0.0001f, settings.lightradiusscale, 1024.0f);
2461 settings.maxbounce = bound(0, settings.maxbounce, 16);
2462 settings.spacing[0] = bound(1, settings.spacing[0], 512);
2463 settings.spacing[1] = bound(1, settings.spacing[1], 512);
2464 settings.spacing[2] = bound(1, settings.spacing[2], 512);
2466 // get the spacing values
2467 spacing[0] = settings.spacing[0];
2468 spacing[1] = settings.spacing[1];
2469 spacing[2] = settings.spacing[2];
2470 ispacing[0] = 1.0f / spacing[0];
2471 ispacing[1] = 1.0f / spacing[1];
2472 ispacing[2] = 1.0f / spacing[2];
2474 // calculate texture size enclosing entire world bounds at the spacing
2475 VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
2476 VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
2477 VectorSubtract(maxs, mins, size);
2478 // now we can calculate the resolution we want
2479 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2480 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2481 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2482 // figure out the exact texture size (honoring power of 2 if required)
2483 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2484 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2485 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2486 if (vid.support.arb_texture_non_power_of_two)
2488 resolution[0] = c[0];
2489 resolution[1] = c[1];
2490 resolution[2] = c[2];
2494 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2495 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2496 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2498 size[0] = spacing[0] * resolution[0];
2499 size[1] = spacing[1] * resolution[1];
2500 size[2] = spacing[2] * resolution[2];
2502 // if dynamic we may or may not want to use the world bounds
2503 // if the dynamic size is smaller than the world bounds, use it instead
2504 if (!settings.staticmode && (r_shadow_bouncegrid_x.integer * r_shadow_bouncegrid_y.integer * r_shadow_bouncegrid_z.integer < resolution[0] * resolution[1] * resolution[2]))
2506 // we know the resolution we want
2507 c[0] = r_shadow_bouncegrid_x.integer;
2508 c[1] = r_shadow_bouncegrid_y.integer;
2509 c[2] = r_shadow_bouncegrid_z.integer;
2510 // now we can calculate the texture size (power of 2 if required)
2511 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2512 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2513 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2514 if (vid.support.arb_texture_non_power_of_two)
2516 resolution[0] = c[0];
2517 resolution[1] = c[1];
2518 resolution[2] = c[2];
2522 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2523 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2524 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2526 size[0] = spacing[0] * resolution[0];
2527 size[1] = spacing[1] * resolution[1];
2528 size[2] = spacing[2] * resolution[2];
2529 // center the rendering on the view
2530 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2531 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2532 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2535 // recalculate the maxs in case the resolution was not satisfactory
2536 VectorAdd(mins, size, maxs);
2538 // if all the settings seem identical to the previous update, return
2539 if (r_shadow_bouncegridtexture && (settings.staticmode || realtime < r_shadow_bouncegridtime + r_shadow_bouncegrid_updateinterval.value) && !memcmp(&r_shadow_bouncegridsettings, &settings, sizeof(settings)))
2542 // store the new settings
2543 r_shadow_bouncegridsettings = settings;
2545 pixelbands = settings.directionalshading ? 8 : 1;
2546 pixelsperband = resolution[0]*resolution[1]*resolution[2];
2547 numpixels = pixelsperband*pixelbands;
2549 // we're going to update the bouncegrid, update the matrix...
2550 memset(m, 0, sizeof(m));
2551 m[0] = 1.0f / size[0];
2552 m[3] = -mins[0] * m[0];
2553 m[5] = 1.0f / size[1];
2554 m[7] = -mins[1] * m[5];
2555 m[10] = 1.0f / size[2];
2556 m[11] = -mins[2] * m[10];
2558 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegridmatrix, m);
2559 // reallocate pixels for this update if needed...
2560 if (r_shadow_bouncegridnumpixels != numpixels || !r_shadow_bouncegridpixels || !r_shadow_bouncegridhighpixels)
2562 if (r_shadow_bouncegridtexture)
2564 R_FreeTexture(r_shadow_bouncegridtexture);
2565 r_shadow_bouncegridtexture = NULL;
2567 r_shadow_bouncegridpixels = (unsigned char *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridpixels, numpixels * sizeof(unsigned char[4]));
2568 r_shadow_bouncegridhighpixels = (float *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridhighpixels, numpixels * sizeof(float[4]));
2570 r_shadow_bouncegridnumpixels = numpixels;
2571 pixels = r_shadow_bouncegridpixels;
2572 highpixels = r_shadow_bouncegridhighpixels;
2573 x = pixelsperband*4;
2574 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2577 memset(pixels + pixelband * x, 128, x);
2579 memset(pixels + pixelband * x, 0, x);
2581 memset(highpixels, 0, numpixels * sizeof(float[4]));
2582 // figure out what we want to interact with
2583 if (settings.hitmodels)
2584 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;// | SUPERCONTENTS_LIQUIDSMASK;
2586 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
2587 maxbounce = settings.maxbounce;
2588 // clear variables that produce warnings otherwise
2589 memset(splatcolor, 0, sizeof(splatcolor));
2590 // iterate world rtlights
2591 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2592 range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
2593 range2 = range + range1;
2595 for (lightindex = 0;lightindex < range2;lightindex++)
2597 if (lightindex < range)
2599 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2602 rtlight = &light->rtlight;
2603 VectorClear(rtlight->photoncolor);
2604 rtlight->photons = 0;
2605 if (!(light->flags & flag))
2607 if (settings.staticmode)
2609 // when static, we skip styled lights because they tend to change...
2610 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2616 rtlight = r_refdef.scene.lights[lightindex - range];
2617 VectorClear(rtlight->photoncolor);
2618 rtlight->photons = 0;
2620 // draw only visible lights (major speedup)
2621 radius = rtlight->radius * settings.lightradiusscale;
2622 cullmins[0] = rtlight->shadoworigin[0] - radius;
2623 cullmins[1] = rtlight->shadoworigin[1] - radius;
2624 cullmins[2] = rtlight->shadoworigin[2] - radius;
2625 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2626 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2627 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2628 if (R_CullBox(cullmins, cullmaxs))
2630 if (r_refdef.scene.worldmodel
2631 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2632 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2634 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2635 if (w * VectorLength2(rtlight->color) == 0.0f)
2637 w *= (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2638 VectorScale(rtlight->color, w, rtlight->photoncolor);
2639 //if (!VectorLength2(rtlight->photoncolor))
2641 // shoot particles from this light
2642 // use a calculation for the number of particles that will not
2643 // vary with lightstyle, otherwise we get randomized particle
2644 // distribution, the seeded random is only consistent for a
2645 // consistent number of particles on this light...
2646 s = rtlight->radius;
2647 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2648 if (lightindex >= range)
2649 lightintensity *= settings.dlightparticlemultiplier;
2650 rtlight->photons = max(0.0f, lightintensity * s * s);
2651 photoncount += rtlight->photons;
2653 photonscaling = (float)settings.photons / max(1, photoncount);
2654 photonresidual = 0.0f;
2655 for (lightindex = 0;lightindex < range2;lightindex++)
2657 if (lightindex < range)
2659 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2662 rtlight = &light->rtlight;
2665 rtlight = r_refdef.scene.lights[lightindex - range];
2666 // skip a light with no photons
2667 if (rtlight->photons == 0.0f)
2669 // skip a light with no photon color)
2670 if (VectorLength2(rtlight->photoncolor) == 0.0f)
2672 photonresidual += rtlight->photons * photonscaling;
2673 shootparticles = (int)bound(0, photonresidual, MAXBOUNCEGRIDPARTICLESPERLIGHT);
2674 if (!shootparticles)
2676 photonresidual -= shootparticles;
2677 radius = rtlight->radius * settings.lightradiusscale;
2678 s = settings.particleintensity / shootparticles;
2679 VectorScale(rtlight->photoncolor, s, baseshotcolor);
2680 r_refdef.stats.bouncegrid_lights++;
2681 r_refdef.stats.bouncegrid_particles += shootparticles;
2682 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2684 if (settings.stablerandom > 0)
2685 seed = lightindex * 11937 + shotparticles;
2686 VectorCopy(baseshotcolor, shotcolor);
2687 VectorCopy(rtlight->shadoworigin, clipstart);
2688 if (settings.stablerandom < 0)
2689 VectorRandom(clipend);
2691 VectorCheeseRandom(clipend);
2692 VectorMA(clipstart, radius, clipend, clipend);
2693 for (bouncecount = 0;;bouncecount++)
2695 r_refdef.stats.bouncegrid_traces++;
2696 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2697 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2698 if (settings.staticmode)
2700 // static mode fires a LOT of rays but none of them are identical, so they are not cached
2701 cliptrace = CL_TraceLine(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), NULL, hitsupercontentsmask, true, false, NULL, true, true);
2705 // dynamic mode fires many rays and most will match the cache from the previous frame
2706 cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask);
2708 if (bouncecount > 0 || settings.includedirectlighting)
2710 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2711 // accumulate average shotcolor
2712 w = VectorLength(shotcolor);
2713 splatcolor[ 0] = shotcolor[0];
2714 splatcolor[ 1] = shotcolor[1];
2715 splatcolor[ 2] = shotcolor[2];
2716 splatcolor[ 3] = 0.0f;
2719 VectorSubtract(clipstart, cliptrace.endpos, clipdiff);
2720 VectorNormalize(clipdiff);
2721 // store bentnormal in case the shader has a use for it
2722 splatcolor[ 4] = clipdiff[0] * w;
2723 splatcolor[ 5] = clipdiff[1] * w;
2724 splatcolor[ 6] = clipdiff[2] * w;
2726 // accumulate directional contributions (+X, +Y, +Z, -X, -Y, -Z)
2727 splatcolor[ 8] = shotcolor[0] * max(0.0f, clipdiff[0]);
2728 splatcolor[ 9] = shotcolor[0] * max(0.0f, clipdiff[1]);
2729 splatcolor[10] = shotcolor[0] * max(0.0f, clipdiff[2]);
2730 splatcolor[11] = 0.0f;
2731 splatcolor[12] = shotcolor[1] * max(0.0f, clipdiff[0]);
2732 splatcolor[13] = shotcolor[1] * max(0.0f, clipdiff[1]);
2733 splatcolor[14] = shotcolor[1] * max(0.0f, clipdiff[2]);
2734 splatcolor[15] = 0.0f;
2735 splatcolor[16] = shotcolor[2] * max(0.0f, clipdiff[0]);
2736 splatcolor[17] = shotcolor[2] * max(0.0f, clipdiff[1]);
2737 splatcolor[18] = shotcolor[2] * max(0.0f, clipdiff[2]);
2738 splatcolor[19] = 0.0f;
2739 splatcolor[20] = shotcolor[0] * max(0.0f, -clipdiff[0]);
2740 splatcolor[21] = shotcolor[0] * max(0.0f, -clipdiff[1]);
2741 splatcolor[22] = shotcolor[0] * max(0.0f, -clipdiff[2]);
2742 splatcolor[23] = 0.0f;
2743 splatcolor[24] = shotcolor[1] * max(0.0f, -clipdiff[0]);
2744 splatcolor[25] = shotcolor[1] * max(0.0f, -clipdiff[1]);
2745 splatcolor[26] = shotcolor[1] * max(0.0f, -clipdiff[2]);
2746 splatcolor[27] = 0.0f;
2747 splatcolor[28] = shotcolor[2] * max(0.0f, -clipdiff[0]);
2748 splatcolor[29] = shotcolor[2] * max(0.0f, -clipdiff[1]);
2749 splatcolor[30] = shotcolor[2] * max(0.0f, -clipdiff[2]);
2750 splatcolor[31] = 0.0f;
2752 // calculate the number of steps we need to traverse this distance
2753 VectorSubtract(cliptrace.endpos, clipstart, stepdelta);
2754 numsteps = (int)(VectorLength(stepdelta) * ispacing[0]);
2755 numsteps = bound(1, numsteps, 1024);
2756 w = 1.0f / numsteps;
2757 VectorScale(stepdelta, w, stepdelta);
2758 VectorMA(clipstart, 0.5f, stepdelta, steppos);
2759 for (step = 0;step < numsteps;step++)
2761 r_refdef.stats.bouncegrid_splats++;
2762 // figure out which texture pixel this is in
2763 texlerp[1][0] = ((steppos[0] - mins[0]) * ispacing[0]) - 0.5f;
2764 texlerp[1][1] = ((steppos[1] - mins[1]) * ispacing[1]) - 0.5f;
2765 texlerp[1][2] = ((steppos[2] - mins[2]) * ispacing[2]) - 0.5f;
2766 tex[0] = (int)floor(texlerp[1][0]);
2767 tex[1] = (int)floor(texlerp[1][1]);
2768 tex[2] = (int)floor(texlerp[1][2]);
2769 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)
2771 // it is within bounds... do the real work now
2772 // calculate the lerp factors
2773 texlerp[1][0] -= tex[0];
2774 texlerp[1][1] -= tex[1];
2775 texlerp[1][2] -= tex[2];
2776 texlerp[0][0] = 1.0f - texlerp[1][0];
2777 texlerp[0][1] = 1.0f - texlerp[1][1];
2778 texlerp[0][2] = 1.0f - texlerp[1][2];
2779 // calculate individual pixel indexes and weights
2780 pixelindex[0] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[0] = (texlerp[0][0]*texlerp[0][1]*texlerp[0][2]);
2781 pixelindex[1] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0]+1);pixelweight[1] = (texlerp[1][0]*texlerp[0][1]*texlerp[0][2]);
2782 pixelindex[2] = (((tex[2] )*resolution[1]+tex[1]+1)*resolution[0]+tex[0] );pixelweight[2] = (texlerp[0][0]*texlerp[1][1]*texlerp[0][2]);
2783 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]);
2784 pixelindex[4] = (((tex[2]+1)*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[4] = (texlerp[0][0]*texlerp[0][1]*texlerp[1][2]);
2785 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]);
2786 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]);
2787 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]);
2788 // update the 8 pixels...
2789 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2791 for (corner = 0;corner < 8;corner++)
2793 // calculate address for pixel
2794 w = pixelweight[corner];
2795 pixel = pixels + 4 * pixelindex[corner] + pixelband * pixelsperband * 4;
2796 highpixel = highpixels + 4 * pixelindex[corner] + pixelband * pixelsperband * 4;
2797 // add to the high precision pixel color
2798 highpixel[0] += (splatcolor[pixelband*4+0]*w);
2799 highpixel[1] += (splatcolor[pixelband*4+1]*w);
2800 highpixel[2] += (splatcolor[pixelband*4+2]*w);
2801 highpixel[3] += (splatcolor[pixelband*4+3]*w);
2802 // flag the low precision pixel as needing to be updated
2804 // advance to next band of coefficients
2805 //pixel += pixelsperband*4;
2806 //highpixel += pixelsperband*4;
2810 VectorAdd(steppos, stepdelta, steppos);
2813 if (cliptrace.fraction >= 1.0f)
2815 r_refdef.stats.bouncegrid_hits++;
2816 if (bouncecount >= maxbounce)
2818 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2819 // also clamp the resulting color to never add energy, even if the user requests extreme values
2820 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2821 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
2823 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
2824 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
2825 surfcolor[0] = min(surfcolor[0], 1.0f);
2826 surfcolor[1] = min(surfcolor[1], 1.0f);
2827 surfcolor[2] = min(surfcolor[2], 1.0f);
2828 VectorMultiply(shotcolor, surfcolor, shotcolor);
2829 if (VectorLength2(baseshotcolor) == 0.0f)
2831 r_refdef.stats.bouncegrid_bounces++;
2832 if (settings.bounceanglediffuse)
2834 // random direction, primarily along plane normal
2835 s = VectorDistance(cliptrace.endpos, clipend);
2836 if (settings.stablerandom < 0)
2837 VectorRandom(clipend);
2839 VectorCheeseRandom(clipend);
2840 VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
2841 VectorNormalize(clipend);
2842 VectorScale(clipend, s, clipend);
2846 // reflect the remaining portion of the line across plane normal
2847 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2848 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2850 // calculate the new line start and end
2851 VectorCopy(cliptrace.endpos, clipstart);
2852 VectorAdd(clipstart, clipend, clipend);
2856 // generate pixels array from highpixels array
2857 // skip first and last columns, rows, and layers as these are blank
2858 // the pixel[3] value was written above, so we can use it to detect only pixels that need to be calculated
2859 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2861 for (z = 1;z < resolution[2]-1;z++)
2863 for (y = 1;y < resolution[1]-1;y++)
2865 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)
2867 // only convert pixels that were hit by photons
2868 if (pixel[3] == 255)
2870 // normalize the bentnormal...
2873 VectorNormalize(highpixel);
2874 c[0] = (int)(highpixel[0]*128.0f+128.0f);
2875 c[1] = (int)(highpixel[1]*128.0f+128.0f);
2876 c[2] = (int)(highpixel[2]*128.0f+128.0f);
2877 c[3] = (int)(highpixel[3]*128.0f+128.0f);
2881 c[0] = (int)(highpixel[0]*256.0f);
2882 c[1] = (int)(highpixel[1]*256.0f);
2883 c[2] = (int)(highpixel[2]*256.0f);
2884 c[3] = (int)(highpixel[3]*256.0f);
2886 pixel[2] = (unsigned char)bound(0, c[0], 255);
2887 pixel[1] = (unsigned char)bound(0, c[1], 255);
2888 pixel[0] = (unsigned char)bound(0, c[2], 255);
2889 pixel[3] = (unsigned char)bound(0, c[3], 255);
2895 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)
2896 R_UpdateTexture(r_shadow_bouncegridtexture, pixels, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2899 VectorCopy(resolution, r_shadow_bouncegridresolution);
2900 r_shadow_bouncegriddirectional = settings.directionalshading;
2901 if (r_shadow_bouncegridtexture)
2902 R_FreeTexture(r_shadow_bouncegridtexture);
2903 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);
2905 r_shadow_bouncegridtime = realtime;
2908 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2910 R_Shadow_RenderMode_Reset();
2911 GL_BlendFunc(GL_ONE, GL_ONE);
2912 GL_DepthRange(0, 1);
2913 GL_DepthTest(r_showshadowvolumes.integer < 2);
2914 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2915 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2916 GL_CullFace(GL_NONE);
2917 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2920 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2922 R_Shadow_RenderMode_Reset();
2923 GL_BlendFunc(GL_ONE, GL_ONE);
2924 GL_DepthRange(0, 1);
2925 GL_DepthTest(r_showlighting.integer < 2);
2926 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2928 GL_DepthFunc(GL_EQUAL);
2929 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2930 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2933 void R_Shadow_RenderMode_End(void)
2935 R_Shadow_RenderMode_Reset();
2936 R_Shadow_RenderMode_ActiveLight(NULL);
2938 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2939 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2942 int bboxedges[12][2] =
2961 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2963 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
2965 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2966 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2967 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2968 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2971 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2972 return true; // invisible
2973 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2974 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2975 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2976 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2977 r_refdef.stats.lights_scissored++;
2981 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2984 const float *vertex3f;
2985 const float *normal3f;
2987 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2988 switch (r_shadow_rendermode)
2990 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2991 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2992 if (VectorLength2(diffusecolor) > 0)
2994 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)
2996 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2997 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2998 if ((dot = DotProduct(n, v)) < 0)
3000 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3001 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
3004 VectorCopy(ambientcolor, color4f);
3005 if (r_refdef.fogenabled)
3008 f = RSurf_FogVertex(vertex3f);
3009 VectorScale(color4f, f, color4f);
3016 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3018 VectorCopy(ambientcolor, color4f);
3019 if (r_refdef.fogenabled)
3022 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3023 f = RSurf_FogVertex(vertex3f);
3024 VectorScale(color4f + 4*i, f, color4f);
3030 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3031 if (VectorLength2(diffusecolor) > 0)
3033 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)
3035 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3036 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3038 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3039 if ((dot = DotProduct(n, v)) < 0)
3041 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3042 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3043 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3044 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3048 color4f[0] = ambientcolor[0] * distintensity;
3049 color4f[1] = ambientcolor[1] * distintensity;
3050 color4f[2] = ambientcolor[2] * distintensity;
3052 if (r_refdef.fogenabled)
3055 f = RSurf_FogVertex(vertex3f);
3056 VectorScale(color4f, f, color4f);
3060 VectorClear(color4f);
3066 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3068 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3069 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3071 color4f[0] = ambientcolor[0] * distintensity;
3072 color4f[1] = ambientcolor[1] * distintensity;
3073 color4f[2] = ambientcolor[2] * distintensity;
3074 if (r_refdef.fogenabled)
3077 f = RSurf_FogVertex(vertex3f);
3078 VectorScale(color4f, f, color4f);
3082 VectorClear(color4f);
3087 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3088 if (VectorLength2(diffusecolor) > 0)
3090 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)
3092 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3093 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3095 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3096 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3097 if ((dot = DotProduct(n, v)) < 0)
3099 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3100 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3101 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3102 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3106 color4f[0] = ambientcolor[0] * distintensity;
3107 color4f[1] = ambientcolor[1] * distintensity;
3108 color4f[2] = ambientcolor[2] * distintensity;
3110 if (r_refdef.fogenabled)
3113 f = RSurf_FogVertex(vertex3f);
3114 VectorScale(color4f, f, color4f);
3118 VectorClear(color4f);
3124 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3126 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3127 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3129 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3130 color4f[0] = ambientcolor[0] * distintensity;
3131 color4f[1] = ambientcolor[1] * distintensity;
3132 color4f[2] = ambientcolor[2] * distintensity;
3133 if (r_refdef.fogenabled)
3136 f = RSurf_FogVertex(vertex3f);
3137 VectorScale(color4f, f, color4f);
3141 VectorClear(color4f);
3151 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3153 // used to display how many times a surface is lit for level design purposes
3154 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3155 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3159 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
3161 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3162 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
3166 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3173 int newnumtriangles;
3177 int maxtriangles = 1024;
3178 int newelements[1024*3];
3179 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3180 for (renders = 0;renders < 4;renders++)
3185 newnumtriangles = 0;
3187 // due to low fillrate on the cards this vertex lighting path is
3188 // designed for, we manually cull all triangles that do not
3189 // contain a lit vertex
3190 // this builds batches of triangles from multiple surfaces and
3191 // renders them at once
3192 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3194 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3196 if (newnumtriangles)
3198 newfirstvertex = min(newfirstvertex, e[0]);
3199 newlastvertex = max(newlastvertex, e[0]);
3203 newfirstvertex = e[0];
3204 newlastvertex = e[0];
3206 newfirstvertex = min(newfirstvertex, e[1]);
3207 newlastvertex = max(newlastvertex, e[1]);
3208 newfirstvertex = min(newfirstvertex, e[2]);
3209 newlastvertex = max(newlastvertex, e[2]);
3215 if (newnumtriangles >= maxtriangles)
3217 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3218 newnumtriangles = 0;
3224 if (newnumtriangles >= 1)
3226 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3229 // if we couldn't find any lit triangles, exit early
3232 // now reduce the intensity for the next overbright pass
3233 // we have to clamp to 0 here incase the drivers have improper
3234 // handling of negative colors
3235 // (some old drivers even have improper handling of >1 color)
3237 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3239 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3241 c[0] = max(0, c[0] - 1);
3242 c[1] = max(0, c[1] - 1);
3243 c[2] = max(0, c[2] - 1);
3255 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
3257 // OpenGL 1.1 path (anything)
3258 float ambientcolorbase[3], diffusecolorbase[3];
3259 float ambientcolorpants[3], diffusecolorpants[3];
3260 float ambientcolorshirt[3], diffusecolorshirt[3];
3261 const float *surfacecolor = rsurface.texture->dlightcolor;
3262 const float *surfacepants = rsurface.colormap_pantscolor;
3263 const float *surfaceshirt = rsurface.colormap_shirtcolor;
3264 rtexture_t *basetexture = rsurface.texture->basetexture;
3265 rtexture_t *pantstexture = rsurface.texture->pantstexture;
3266 rtexture_t *shirttexture = rsurface.texture->shirttexture;
3267 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3268 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3269 ambientscale *= 2 * r_refdef.view.colorscale;
3270 diffusescale *= 2 * r_refdef.view.colorscale;
3271 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3272 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3273 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3274 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3275 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3276 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
3277 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3278 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
3279 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3280 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
3281 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
3282 R_Mesh_TexBind(0, basetexture);
3283 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
3284 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
3285 switch(r_shadow_rendermode)
3287 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3288 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
3289 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3290 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3291 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3293 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3294 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
3295 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
3296 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
3297 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3299 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3300 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
3301 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3302 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3303 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3305 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3310 //R_Mesh_TexBind(0, basetexture);
3311 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
3314 R_Mesh_TexBind(0, pantstexture);
3315 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
3319 R_Mesh_TexBind(0, shirttexture);
3320 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
3324 extern cvar_t gl_lightmaps;
3325 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3327 float ambientscale, diffusescale, specularscale;
3329 float lightcolor[3];
3330 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
3331 ambientscale = rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient;
3332 diffusescale = rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient);
3333 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3334 if (!r_shadow_usenormalmap.integer)
3336 ambientscale += 1.0f * diffusescale;
3340 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
3342 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
3345 VectorNegate(lightcolor, lightcolor);
3346 GL_BlendEquationSubtract(true);
3348 RSurf_SetupDepthAndCulling();
3349 switch (r_shadow_rendermode)
3351 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3352 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3353 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
3355 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3356 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
3358 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3359 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3360 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3361 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3362 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
3365 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3369 GL_BlendEquationSubtract(false);
3372 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)
3374 matrix4x4_t tempmatrix = *matrix;
3375 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3377 // if this light has been compiled before, free the associated data
3378 R_RTLight_Uncompile(rtlight);
3380 // clear it completely to avoid any lingering data
3381 memset(rtlight, 0, sizeof(*rtlight));
3383 // copy the properties
3384 rtlight->matrix_lighttoworld = tempmatrix;
3385 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3386 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3387 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3388 VectorCopy(color, rtlight->color);
3389 rtlight->cubemapname[0] = 0;
3390 if (cubemapname && cubemapname[0])
3391 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3392 rtlight->shadow = shadow;
3393 rtlight->corona = corona;
3394 rtlight->style = style;
3395 rtlight->isstatic = isstatic;
3396 rtlight->coronasizescale = coronasizescale;
3397 rtlight->ambientscale = ambientscale;
3398 rtlight->diffusescale = diffusescale;
3399 rtlight->specularscale = specularscale;
3400 rtlight->flags = flags;
3402 // compute derived data
3403 //rtlight->cullradius = rtlight->radius;
3404 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3405 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3406 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3407 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3408 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3409 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3410 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3413 // compiles rtlight geometry
3414 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3415 void R_RTLight_Compile(rtlight_t *rtlight)
3418 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3419 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3420 entity_render_t *ent = r_refdef.scene.worldentity;
3421 dp_model_t *model = r_refdef.scene.worldmodel;
3422 unsigned char *data;
3425 // compile the light
3426 rtlight->compiled = true;
3427 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3428 rtlight->static_numleafs = 0;
3429 rtlight->static_numleafpvsbytes = 0;
3430 rtlight->static_leaflist = NULL;
3431 rtlight->static_leafpvs = NULL;
3432 rtlight->static_numsurfaces = 0;
3433 rtlight->static_surfacelist = NULL;
3434 rtlight->static_shadowmap_receivers = 0x3F;
3435 rtlight->static_shadowmap_casters = 0x3F;
3436 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3437 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3438 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3439 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3440 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3441 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3443 if (model && model->GetLightInfo)
3445 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3446 r_shadow_compilingrtlight = rtlight;
3447 R_FrameData_SetMark();
3448 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);
3449 R_FrameData_ReturnToMark();
3450 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3451 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3452 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3453 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3454 rtlight->static_numsurfaces = numsurfaces;
3455 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3456 rtlight->static_numleafs = numleafs;
3457 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3458 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3459 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3460 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3461 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3462 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3463 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3464 if (rtlight->static_numsurfaces)
3465 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3466 if (rtlight->static_numleafs)
3467 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3468 if (rtlight->static_numleafpvsbytes)
3469 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3470 if (rtlight->static_numshadowtrispvsbytes)
3471 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3472 if (rtlight->static_numlighttrispvsbytes)
3473 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3474 R_FrameData_SetMark();
3475 switch (rtlight->shadowmode)
3477 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3478 if (model->CompileShadowMap && rtlight->shadow)
3479 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3482 if (model->CompileShadowVolume && rtlight->shadow)
3483 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3486 R_FrameData_ReturnToMark();
3487 // now we're done compiling the rtlight
3488 r_shadow_compilingrtlight = NULL;
3492 // use smallest available cullradius - box radius or light radius
3493 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3494 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3496 shadowzpasstris = 0;
3497 if (rtlight->static_meshchain_shadow_zpass)
3498 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3499 shadowzpasstris += mesh->numtriangles;
3501 shadowzfailtris = 0;
3502 if (rtlight->static_meshchain_shadow_zfail)
3503 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3504 shadowzfailtris += mesh->numtriangles;
3507 if (rtlight->static_numlighttrispvsbytes)
3508 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3509 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3513 if (rtlight->static_numlighttrispvsbytes)
3514 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3515 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3518 if (developer_extra.integer)
3519 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);
3522 void R_RTLight_Uncompile(rtlight_t *rtlight)
3524 if (rtlight->compiled)
3526 if (rtlight->static_meshchain_shadow_zpass)
3527 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3528 rtlight->static_meshchain_shadow_zpass = NULL;
3529 if (rtlight->static_meshchain_shadow_zfail)
3530 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3531 rtlight->static_meshchain_shadow_zfail = NULL;
3532 if (rtlight->static_meshchain_shadow_shadowmap)
3533 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3534 rtlight->static_meshchain_shadow_shadowmap = NULL;
3535 // these allocations are grouped
3536 if (rtlight->static_surfacelist)
3537 Mem_Free(rtlight->static_surfacelist);
3538 rtlight->static_numleafs = 0;
3539 rtlight->static_numleafpvsbytes = 0;
3540 rtlight->static_leaflist = NULL;
3541 rtlight->static_leafpvs = NULL;
3542 rtlight->static_numsurfaces = 0;
3543 rtlight->static_surfacelist = NULL;
3544 rtlight->static_numshadowtrispvsbytes = 0;
3545 rtlight->static_shadowtrispvs = NULL;
3546 rtlight->static_numlighttrispvsbytes = 0;
3547 rtlight->static_lighttrispvs = NULL;
3548 rtlight->compiled = false;
3552 void R_Shadow_UncompileWorldLights(void)
3556 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3557 for (lightindex = 0;lightindex < range;lightindex++)
3559 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3562 R_RTLight_Uncompile(&light->rtlight);
3566 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3570 // reset the count of frustum planes
3571 // see rtlight->cached_frustumplanes definition for how much this array
3573 rtlight->cached_numfrustumplanes = 0;
3575 if (r_trippy.integer)
3578 // haven't implemented a culling path for ortho rendering
3579 if (!r_refdef.view.useperspective)
3581 // check if the light is on screen and copy the 4 planes if it is
3582 for (i = 0;i < 4;i++)
3583 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3586 for (i = 0;i < 4;i++)
3587 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3592 // generate a deformed frustum that includes the light origin, this is
3593 // used to cull shadow casting surfaces that can not possibly cast a
3594 // shadow onto the visible light-receiving surfaces, which can be a
3597 // if the light origin is onscreen the result will be 4 planes exactly
3598 // if the light origin is offscreen on only one axis the result will
3599 // be exactly 5 planes (split-side case)
3600 // if the light origin is offscreen on two axes the result will be
3601 // exactly 4 planes (stretched corner case)
3602 for (i = 0;i < 4;i++)
3604 // quickly reject standard frustum planes that put the light
3605 // origin outside the frustum
3606 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3609 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3611 // if all the standard frustum planes were accepted, the light is onscreen
3612 // otherwise we need to generate some more planes below...
3613 if (rtlight->cached_numfrustumplanes < 4)
3615 // at least one of the stock frustum planes failed, so we need to
3616 // create one or two custom planes to enclose the light origin
3617 for (i = 0;i < 4;i++)
3619 // create a plane using the view origin and light origin, and a
3620 // single point from the frustum corner set
3621 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3622 VectorNormalize(plane.normal);
3623 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3624 // see if this plane is backwards and flip it if so
3625 for (j = 0;j < 4;j++)
3626 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3630 VectorNegate(plane.normal, plane.normal);
3632 // flipped plane, test again to see if it is now valid
3633 for (j = 0;j < 4;j++)
3634 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3636 // if the plane is still not valid, then it is dividing the
3637 // frustum and has to be rejected
3641 // we have created a valid plane, compute extra info
3642 PlaneClassify(&plane);
3644 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3646 // if we've found 5 frustum planes then we have constructed a
3647 // proper split-side case and do not need to keep searching for
3648 // planes to enclose the light origin
3649 if (rtlight->cached_numfrustumplanes == 5)
3657 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3659 plane = rtlight->cached_frustumplanes[i];
3660 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));
3665 // now add the light-space box planes if the light box is rotated, as any
3666 // caster outside the oriented light box is irrelevant (even if it passed
3667 // the worldspace light box, which is axial)
3668 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3670 for (i = 0;i < 6;i++)
3674 v[i >> 1] = (i & 1) ? -1 : 1;
3675 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3676 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3677 plane.dist = VectorNormalizeLength(plane.normal);
3678 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3679 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3685 // add the world-space reduced box planes
3686 for (i = 0;i < 6;i++)
3688 VectorClear(plane.normal);
3689 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3690 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3691 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3700 // reduce all plane distances to tightly fit the rtlight cull box, which
3702 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3703 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3704 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3705 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3706 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3707 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3708 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3709 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3710 oldnum = rtlight->cached_numfrustumplanes;
3711 rtlight->cached_numfrustumplanes = 0;
3712 for (j = 0;j < oldnum;j++)
3714 // find the nearest point on the box to this plane
3715 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3716 for (i = 1;i < 8;i++)
3718 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3719 if (bestdist > dist)
3722 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);
3723 // if the nearest point is near or behind the plane, we want this
3724 // plane, otherwise the plane is useless as it won't cull anything
3725 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3727 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3728 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3735 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3739 RSurf_ActiveWorldEntity();
3741 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3744 GL_CullFace(GL_NONE);
3745 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3746 for (;mesh;mesh = mesh->next)
3748 if (!mesh->sidetotals[r_shadow_shadowmapside])
3750 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3751 if (mesh->vertex3fbuffer)
3752 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3754 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3755 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);
3759 else if (r_refdef.scene.worldentity->model)
3760 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);
3762 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3765 static void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3767 qboolean zpass = false;
3770 int surfacelistindex;
3771 msurface_t *surface;
3773 // if triangle neighbors are disabled, shadowvolumes are disabled
3774 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
3777 RSurf_ActiveWorldEntity();
3779 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3782 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3784 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3785 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3787 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3788 for (;mesh;mesh = mesh->next)
3790 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3791 if (mesh->vertex3fbuffer)
3792 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3794 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3795 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3797 // increment stencil if frontface is infront of depthbuffer
3798 GL_CullFace(r_refdef.view.cullface_back);
3799 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3800 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);
3801 // decrement stencil if backface is infront of depthbuffer
3802 GL_CullFace(r_refdef.view.cullface_front);
3803 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3805 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3807 // decrement stencil if backface is behind depthbuffer
3808 GL_CullFace(r_refdef.view.cullface_front);
3809 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3810 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);
3811 // increment stencil if frontface is behind depthbuffer
3812 GL_CullFace(r_refdef.view.cullface_back);
3813 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3815 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);
3819 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3821 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3822 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3823 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3825 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3826 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3827 if (CHECKPVSBIT(trispvs, t))
3828 shadowmarklist[numshadowmark++] = t;
3830 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);
3832 else if (numsurfaces)
3834 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);
3837 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3840 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3842 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3843 vec_t relativeshadowradius;
3844 RSurf_ActiveModelEntity(ent, false, false, false);
3845 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3846 // we need to re-init the shader for each entity because the matrix changed
3847 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3848 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3849 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3850 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3851 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3852 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3853 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3854 switch (r_shadow_rendermode)
3856 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3857 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3860 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3863 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3866 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3868 // set up properties for rendering light onto this entity
3869 RSurf_ActiveModelEntity(ent, true, true, false);
3870 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3871 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3872 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3873 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3876 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3878 if (!r_refdef.scene.worldmodel->DrawLight)
3881 // set up properties for rendering light onto this entity
3882 RSurf_ActiveWorldEntity();
3883 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3884 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3885 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3886 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3888 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3890 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3893 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
3895 dp_model_t *model = ent->model;
3896 if (!model->DrawLight)
3899 R_Shadow_SetupEntityLight(ent);
3901 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3903 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3906 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
3910 int numleafs, numsurfaces;
3911 int *leaflist, *surfacelist;
3912 unsigned char *leafpvs;
3913 unsigned char *shadowtrispvs;
3914 unsigned char *lighttrispvs;
3915 //unsigned char *surfacesides;
3916 int numlightentities;
3917 int numlightentities_noselfshadow;
3918 int numshadowentities;
3919 int numshadowentities_noselfshadow;
3920 static entity_render_t *lightentities[MAX_EDICTS];
3921 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3922 static entity_render_t *shadowentities[MAX_EDICTS];
3923 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3926 rtlight->draw = false;
3927 rtlight->cached_numlightentities = 0;
3928 rtlight->cached_numlightentities_noselfshadow = 0;
3929 rtlight->cached_numshadowentities = 0;
3930 rtlight->cached_numshadowentities_noselfshadow = 0;
3931 rtlight->cached_numsurfaces = 0;
3932 rtlight->cached_lightentities = NULL;
3933 rtlight->cached_lightentities_noselfshadow = NULL;
3934 rtlight->cached_shadowentities = NULL;
3935 rtlight->cached_shadowentities_noselfshadow = NULL;
3936 rtlight->cached_shadowtrispvs = NULL;
3937 rtlight->cached_lighttrispvs = NULL;
3938 rtlight->cached_surfacelist = NULL;
3940 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3941 // skip lights that are basically invisible (color 0 0 0)
3942 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3944 // loading is done before visibility checks because loading should happen
3945 // all at once at the start of a level, not when it stalls gameplay.
3946 // (especially important to benchmarks)
3948 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3950 if (rtlight->compiled)
3951 R_RTLight_Uncompile(rtlight);
3952 R_RTLight_Compile(rtlight);
3956 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3958 // look up the light style value at this time
3959 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3960 VectorScale(rtlight->color, f, rtlight->currentcolor);
3962 if (rtlight->selected)
3964 f = 2 + sin(realtime * M_PI * 4.0);
3965 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3969 // if lightstyle is currently off, don't draw the light
3970 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3973 // skip processing on corona-only lights
3977 // if the light box is offscreen, skip it
3978 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3981 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3982 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3984 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3986 // don't allow lights to be drawn if using r_shadow_bouncegrid 2, except if we're using static bouncegrid where dynamic lights still need to draw
3987 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
3990 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3992 // compiled light, world available and can receive realtime lighting
3993 // retrieve leaf information
3994 numleafs = rtlight->static_numleafs;
3995 leaflist = rtlight->static_leaflist;
3996 leafpvs = rtlight->static_leafpvs;
3997 numsurfaces = rtlight->static_numsurfaces;
3998 surfacelist = rtlight->static_surfacelist;
3999 //surfacesides = NULL;
4000 shadowtrispvs = rtlight->static_shadowtrispvs;
4001 lighttrispvs = rtlight->static_lighttrispvs;
4003 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4005 // dynamic light, world available and can receive realtime lighting
4006 // calculate lit surfaces and leafs
4007 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);
4008 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4009 leaflist = r_shadow_buffer_leaflist;
4010 leafpvs = r_shadow_buffer_leafpvs;
4011 surfacelist = r_shadow_buffer_surfacelist;
4012 //surfacesides = r_shadow_buffer_surfacesides;
4013 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4014 lighttrispvs = r_shadow_buffer_lighttrispvs;
4015 // if the reduced leaf bounds are offscreen, skip it
4016 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4027 //surfacesides = NULL;
4028 shadowtrispvs = NULL;
4029 lighttrispvs = NULL;
4031 // check if light is illuminating any visible leafs
4034 for (i = 0;i < numleafs;i++)
4035 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4041 // make a list of lit entities and shadow casting entities
4042 numlightentities = 0;
4043 numlightentities_noselfshadow = 0;
4044 numshadowentities = 0;
4045 numshadowentities_noselfshadow = 0;
4047 // add dynamic entities that are lit by the light
4048 for (i = 0;i < r_refdef.scene.numentities;i++)
4051 entity_render_t *ent = r_refdef.scene.entities[i];
4053 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4055 // skip the object entirely if it is not within the valid
4056 // shadow-casting region (which includes the lit region)
4057 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
4059 if (!(model = ent->model))
4061 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4063 // this entity wants to receive light, is visible, and is
4064 // inside the light box
4065 // TODO: check if the surfaces in the model can receive light
4066 // so now check if it's in a leaf seen by the light
4067 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))
4069 if (ent->flags & RENDER_NOSELFSHADOW)
4070 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
4072 lightentities[numlightentities++] = ent;
4073 // since it is lit, it probably also casts a shadow...
4074 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4075 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4076 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4078 // note: exterior models without the RENDER_NOSELFSHADOW
4079 // flag still create a RENDER_NOSELFSHADOW shadow but
4080 // are lit normally, this means that they are
4081 // self-shadowing but do not shadow other
4082 // RENDER_NOSELFSHADOW entities such as the gun
4083 // (very weird, but keeps the player shadow off the gun)
4084 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4085 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4087 shadowentities[numshadowentities++] = ent;
4090 else if (ent->flags & RENDER_SHADOW)
4092 // this entity is not receiving light, but may still need to
4094 // TODO: check if the surfaces in the model can cast shadow
4095 // now check if it is in a leaf seen by the light
4096 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))
4098 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4099 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4100 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4102 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4103 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4105 shadowentities[numshadowentities++] = ent;
4110 // return if there's nothing at all to light
4111 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4114 // count this light in the r_speeds
4115 r_refdef.stats.lights++;
4117 // flag it as worth drawing later
4118 rtlight->draw = true;
4120 // cache all the animated entities that cast a shadow but are not visible
4121 for (i = 0;i < numshadowentities;i++)
4122 if (!shadowentities[i]->animcache_vertex3f)
4123 R_AnimCache_GetEntity(shadowentities[i], false, false);
4124 for (i = 0;i < numshadowentities_noselfshadow;i++)
4125 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
4126 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4128 // allocate some temporary memory for rendering this light later in the frame
4129 // reusable buffers need to be copied, static data can be used as-is
4130 rtlight->cached_numlightentities = numlightentities;
4131 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
4132 rtlight->cached_numshadowentities = numshadowentities;
4133 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4134 rtlight->cached_numsurfaces = numsurfaces;
4135 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4136 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4137 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4138 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4139 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4141 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4142 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4143 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4144 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4145 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4149 // compiled light data
4150 rtlight->cached_shadowtrispvs = shadowtrispvs;
4151 rtlight->cached_lighttrispvs = lighttrispvs;
4152 rtlight->cached_surfacelist = surfacelist;
4156 static void R_Shadow_DrawLight(rtlight_t *rtlight)
4160 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4161 int numlightentities;
4162 int numlightentities_noselfshadow;
4163 int numshadowentities;
4164 int numshadowentities_noselfshadow;
4165 entity_render_t **lightentities;
4166 entity_render_t **lightentities_noselfshadow;
4167 entity_render_t **shadowentities;
4168 entity_render_t **shadowentities_noselfshadow;
4170 static unsigned char entitysides[MAX_EDICTS];
4171 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4172 vec3_t nearestpoint;
4174 qboolean castshadows;
4177 // check if we cached this light this frame (meaning it is worth drawing)
4181 numlightentities = rtlight->cached_numlightentities;
4182 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4183 numshadowentities = rtlight->cached_numshadowentities;
4184 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4185 numsurfaces = rtlight->cached_numsurfaces;
4186 lightentities = rtlight->cached_lightentities;
4187 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4188 shadowentities = rtlight->cached_shadowentities;
4189 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4190 shadowtrispvs = rtlight->cached_shadowtrispvs;
4191 lighttrispvs = rtlight->cached_lighttrispvs;
4192 surfacelist = rtlight->cached_surfacelist;
4194 // set up a scissor rectangle for this light
4195 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4198 // don't let sound skip if going slow
4199 if (r_refdef.scene.extraupdate)
4202 // make this the active rtlight for rendering purposes
4203 R_Shadow_RenderMode_ActiveLight(rtlight);
4205 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4207 // optionally draw visible shape of the shadow volumes
4208 // for performance analysis by level designers
4209 R_Shadow_RenderMode_VisibleShadowVolumes();
4211 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4212 for (i = 0;i < numshadowentities;i++)
4213 R_Shadow_DrawEntityShadow(shadowentities[i]);
4214 for (i = 0;i < numshadowentities_noselfshadow;i++)
4215 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4216 R_Shadow_RenderMode_VisibleLighting(false, false);
4219 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4221 // optionally draw the illuminated areas
4222 // for performance analysis by level designers
4223 R_Shadow_RenderMode_VisibleLighting(false, false);
4225 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4226 for (i = 0;i < numlightentities;i++)
4227 R_Shadow_DrawEntityLight(lightentities[i]);
4228 for (i = 0;i < numlightentities_noselfshadow;i++)
4229 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4232 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4234 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4235 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4236 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4237 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4239 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
4240 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4241 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4243 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4249 int receivermask = 0;
4250 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4251 Matrix4x4_Abs(&radiustolight);
4253 r_shadow_shadowmaplod = 0;
4254 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4255 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
4256 r_shadow_shadowmaplod = i;
4258 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4260 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4262 surfacesides = NULL;
4265 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4267 castermask = rtlight->static_shadowmap_casters;
4268 receivermask = rtlight->static_shadowmap_receivers;
4272 surfacesides = r_shadow_buffer_surfacesides;
4273 for(i = 0;i < numsurfaces;i++)
4275 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4276 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4277 castermask |= surfacesides[i];
4278 receivermask |= surfacesides[i];
4282 if (receivermask < 0x3F)
4284 for (i = 0;i < numlightentities;i++)
4285 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4286 if (receivermask < 0x3F)
4287 for(i = 0; i < numlightentities_noselfshadow;i++)
4288 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4291 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4295 for (i = 0;i < numshadowentities;i++)
4296 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4297 for (i = 0;i < numshadowentities_noselfshadow;i++)
4298 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4301 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4303 // render shadow casters into 6 sided depth texture
4304 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4306 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
4307 if (! (castermask & (1 << side))) continue;
4309 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4310 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4311 R_Shadow_DrawEntityShadow(shadowentities[i]);
4314 if (numlightentities_noselfshadow)
4316 // render lighting using the depth texture as shadowmap
4317 // draw lighting in the unmasked areas
4318 R_Shadow_RenderMode_Lighting(false, false, true);
4319 for (i = 0;i < numlightentities_noselfshadow;i++)
4320 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4323 // render shadow casters into 6 sided depth texture
4324 if (numshadowentities_noselfshadow)
4326 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4328 R_Shadow_RenderMode_ShadowMap(side, 0, size);
4329 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
4330 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4334 // render lighting using the depth texture as shadowmap
4335 // draw lighting in the unmasked areas
4336 R_Shadow_RenderMode_Lighting(false, false, true);
4337 // draw lighting in the unmasked areas
4339 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4340 for (i = 0;i < numlightentities;i++)
4341 R_Shadow_DrawEntityLight(lightentities[i]);
4343 else if (castshadows && vid.stencil)
4345 // draw stencil shadow volumes to mask off pixels that are in shadow
4346 // so that they won't receive lighting
4347 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4348 R_Shadow_ClearStencil();
4351 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4352 for (i = 0;i < numshadowentities;i++)
4353 R_Shadow_DrawEntityShadow(shadowentities[i]);
4355 // draw lighting in the unmasked areas
4356 R_Shadow_RenderMode_Lighting(true, false, false);
4357 for (i = 0;i < numlightentities_noselfshadow;i++)
4358 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4360 for (i = 0;i < numshadowentities_noselfshadow;i++)
4361 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4363 // draw lighting in the unmasked areas
4364 R_Shadow_RenderMode_Lighting(true, false, false);
4366 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4367 for (i = 0;i < numlightentities;i++)
4368 R_Shadow_DrawEntityLight(lightentities[i]);
4372 // draw lighting in the unmasked areas
4373 R_Shadow_RenderMode_Lighting(false, false, false);
4375 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4376 for (i = 0;i < numlightentities;i++)
4377 R_Shadow_DrawEntityLight(lightentities[i]);
4378 for (i = 0;i < numlightentities_noselfshadow;i++)
4379 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4382 if (r_shadow_usingdeferredprepass)
4384 // when rendering deferred lighting, we simply rasterize the box
4385 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4386 R_Shadow_RenderMode_DrawDeferredLight(false, true);
4387 else if (castshadows && vid.stencil)
4388 R_Shadow_RenderMode_DrawDeferredLight(true, false);
4390 R_Shadow_RenderMode_DrawDeferredLight(false, false);
4394 static void R_Shadow_FreeDeferred(void)
4396 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
4397 r_shadow_prepassgeometryfbo = 0;
4399 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
4400 r_shadow_prepasslightingdiffusespecularfbo = 0;
4402 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
4403 r_shadow_prepasslightingdiffusefbo = 0;
4405 if (r_shadow_prepassgeometrydepthbuffer)
4406 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
4407 r_shadow_prepassgeometrydepthbuffer = NULL;
4409 if (r_shadow_prepassgeometrynormalmaptexture)
4410 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4411 r_shadow_prepassgeometrynormalmaptexture = NULL;
4413 if (r_shadow_prepasslightingdiffusetexture)
4414 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
4415 r_shadow_prepasslightingdiffusetexture = NULL;
4417 if (r_shadow_prepasslightingspeculartexture)
4418 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4419 r_shadow_prepasslightingspeculartexture = NULL;
4422 void R_Shadow_DrawPrepass(void)
4430 entity_render_t *ent;
4431 float clearcolor[4];
4433 R_Mesh_ResetTextureState();
4435 GL_ColorMask(1,1,1,1);
4436 GL_BlendFunc(GL_ONE, GL_ZERO);
4439 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4440 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4441 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4442 if (r_timereport_active)
4443 R_TimeReport("prepasscleargeom");
4445 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4446 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4447 if (r_timereport_active)
4448 R_TimeReport("prepassworld");
4450 for (i = 0;i < r_refdef.scene.numentities;i++)
4452 if (!r_refdef.viewcache.entityvisible[i])
4454 ent = r_refdef.scene.entities[i];
4455 if (ent->model && ent->model->DrawPrepass != NULL)
4456 ent->model->DrawPrepass(ent);
4459 if (r_timereport_active)
4460 R_TimeReport("prepassmodels");
4462 GL_DepthMask(false);
4463 GL_ColorMask(1,1,1,1);
4466 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4467 Vector4Set(clearcolor, 0, 0, 0, 0);
4468 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4469 if (r_timereport_active)
4470 R_TimeReport("prepassclearlit");
4472 R_Shadow_RenderMode_Begin();
4474 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4475 if (r_shadow_debuglight.integer >= 0)
4477 lightindex = r_shadow_debuglight.integer;
4478 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4479 if (light && (light->flags & flag) && light->rtlight.draw)
4480 R_Shadow_DrawLight(&light->rtlight);
4484 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4485 for (lightindex = 0;lightindex < range;lightindex++)
4487 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4488 if (light && (light->flags & flag) && light->rtlight.draw)
4489 R_Shadow_DrawLight(&light->rtlight);
4492 if (r_refdef.scene.rtdlight)
4493 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4494 if (r_refdef.scene.lights[lnum]->draw)
4495 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4497 R_Shadow_RenderMode_End();
4499 if (r_timereport_active)
4500 R_TimeReport("prepasslights");
4503 void R_Shadow_DrawLightSprites(void);
4504 void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
4513 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4514 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4515 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
4516 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4517 r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) ||
4518 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4519 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4520 R_Shadow_FreeShadowMaps();
4522 r_shadow_fb_fbo = fbo;
4523 r_shadow_fb_depthtexture = depthtexture;
4524 r_shadow_fb_colortexture = colortexture;
4526 r_shadow_usingshadowmaportho = false;
4528 switch (vid.renderpath)
4530 case RENDERPATH_GL20:
4531 case RENDERPATH_D3D9:
4532 case RENDERPATH_D3D10:
4533 case RENDERPATH_D3D11:
4534 case RENDERPATH_SOFT:
4536 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4538 r_shadow_usingdeferredprepass = false;
4539 if (r_shadow_prepass_width)
4540 R_Shadow_FreeDeferred();
4541 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4545 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4547 R_Shadow_FreeDeferred();
4549 r_shadow_usingdeferredprepass = true;
4550 r_shadow_prepass_width = vid.width;
4551 r_shadow_prepass_height = vid.height;
4552 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
4553 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);
4554 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);
4555 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);
4557 // set up the geometry pass fbo (depth + normalmap)
4558 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4559 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4560 // render depth into a renderbuffer and other important properties into the normalmap texture
4562 // set up the lighting pass fbo (diffuse + specular)
4563 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4564 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4565 // render diffuse into one texture and specular into another,
4566 // with depth and normalmap bound as textures,
4567 // with depth bound as attachment as well
4569 // set up the lighting pass fbo (diffuse)
4570 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4571 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4572 // render diffuse into one texture,
4573 // with depth and normalmap bound as textures,
4574 // with depth bound as attachment as well
4578 case RENDERPATH_GL11:
4579 case RENDERPATH_GL13:
4580 case RENDERPATH_GLES1:
4581 case RENDERPATH_GLES2:
4582 r_shadow_usingdeferredprepass = false;
4586 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);
4588 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4589 if (r_shadow_debuglight.integer >= 0)
4591 lightindex = r_shadow_debuglight.integer;
4592 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4594 R_Shadow_PrepareLight(&light->rtlight);
4598 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4599 for (lightindex = 0;lightindex < range;lightindex++)
4601 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4602 if (light && (light->flags & flag))
4603 R_Shadow_PrepareLight(&light->rtlight);
4606 if (r_refdef.scene.rtdlight)
4608 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4609 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4611 else if(gl_flashblend.integer)
4613 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4615 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4616 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4617 VectorScale(rtlight->color, f, rtlight->currentcolor);
4621 if (r_editlights.integer)
4622 R_Shadow_DrawLightSprites();
4625 void R_Shadow_DrawLights(void)
4633 R_Shadow_RenderMode_Begin();
4635 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4636 if (r_shadow_debuglight.integer >= 0)
4638 lightindex = r_shadow_debuglight.integer;
4639 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4641 R_Shadow_DrawLight(&light->rtlight);
4645 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4646 for (lightindex = 0;lightindex < range;lightindex++)
4648 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4649 if (light && (light->flags & flag))
4650 R_Shadow_DrawLight(&light->rtlight);
4653 if (r_refdef.scene.rtdlight)
4654 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4655 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4657 R_Shadow_RenderMode_End();
4660 void R_Shadow_PrepareModelShadows(void)
4663 float scale, size, radius, dot1, dot2;
4664 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4665 entity_render_t *ent;
4667 if (!r_refdef.scene.numentities)
4670 switch (r_shadow_shadowmode)
4672 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4673 if (r_shadows.integer >= 2)
4676 case R_SHADOW_SHADOWMODE_STENCIL:
4677 for (i = 0;i < r_refdef.scene.numentities;i++)
4679 ent = r_refdef.scene.entities[i];
4680 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4681 R_AnimCache_GetEntity(ent, false, false);
4688 size = 2*r_shadow_shadowmapmaxsize;
4689 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4690 radius = 0.5f * size / scale;
4692 Math_atov(r_shadows_throwdirection.string, shadowdir);
4693 VectorNormalize(shadowdir);
4694 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4695 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4696 if (fabs(dot1) <= fabs(dot2))
4697 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4699 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4700 VectorNormalize(shadowforward);
4701 CrossProduct(shadowdir, shadowforward, shadowright);
4702 Math_atov(r_shadows_focus.string, shadowfocus);
4703 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4704 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4705 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4706 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4707 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4709 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4711 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4712 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4713 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4714 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4715 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4716 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4718 for (i = 0;i < r_refdef.scene.numentities;i++)
4720 ent = r_refdef.scene.entities[i];
4721 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4723 // cast shadows from anything of the map (submodels are optional)
4724 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4725 R_AnimCache_GetEntity(ent, false, false);
4729 void R_DrawModelShadowMaps(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
4732 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4733 entity_render_t *ent;
4734 vec3_t relativelightorigin;
4735 vec3_t relativelightdirection, relativeforward, relativeright;
4736 vec3_t relativeshadowmins, relativeshadowmaxs;
4737 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4739 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4740 r_viewport_t viewport;
4741 GLuint shadowfbo = 0;
4742 float clearcolor[4];
4744 if (!r_refdef.scene.numentities)
4747 switch (r_shadow_shadowmode)
4749 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4755 r_shadow_fb_fbo = fbo;
4756 r_shadow_fb_depthtexture = depthtexture;
4757 r_shadow_fb_colortexture = colortexture;
4759 R_ResetViewRendering3D(fbo, depthtexture, colortexture);
4760 R_Shadow_RenderMode_Begin();
4761 R_Shadow_RenderMode_ActiveLight(NULL);
4763 switch (r_shadow_shadowmode)
4765 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4766 if (!r_shadow_shadowmap2ddepthtexture)
4767 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4768 shadowfbo = r_shadow_fbo2d;
4769 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
4770 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
4771 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4777 size = 2*r_shadow_shadowmapmaxsize;
4778 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4779 radius = 0.5f / scale;
4780 nearclip = -r_shadows_throwdistance.value;
4781 farclip = r_shadows_throwdistance.value;
4782 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4784 r_shadow_shadowmap_parameters[0] = size;
4785 r_shadow_shadowmap_parameters[1] = size;
4786 r_shadow_shadowmap_parameters[2] = 1.0;
4787 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4789 Math_atov(r_shadows_throwdirection.string, shadowdir);
4790 VectorNormalize(shadowdir);
4791 Math_atov(r_shadows_focus.string, shadowfocus);
4792 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4793 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4794 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4795 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4796 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4797 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4798 if (fabs(dot1) <= fabs(dot2))
4799 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4801 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4802 VectorNormalize(shadowforward);
4803 VectorM(scale, shadowforward, &m[0]);
4804 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4806 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4807 CrossProduct(shadowdir, shadowforward, shadowright);
4808 VectorM(scale, shadowright, &m[4]);
4809 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4810 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4811 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4812 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4813 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4814 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4816 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4818 if (r_shadow_shadowmap2ddepthbuffer)
4819 R_Mesh_SetRenderTargets(shadowfbo, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
4821 R_Mesh_SetRenderTargets(shadowfbo, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
4822 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL);
4823 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4826 R_SetViewport(&viewport);
4827 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4828 Vector4Set(clearcolor, 1,1,1,1);
4829 // in D3D9 we have to render to a color texture shadowmap
4830 // in GL we render directly to a depth texture only
4831 if (r_shadow_shadowmap2ddepthbuffer)
4832 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4834 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4835 // render into a slightly restricted region so that the borders of the
4836 // shadowmap area fade away, rather than streaking across everything
4837 // outside the usable area
4838 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4842 R_Mesh_SetRenderTargets(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture, NULL, NULL, NULL);
4843 R_SetupShader_ShowDepth(true);
4844 GL_ColorMask(1,1,1,1);
4845 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4848 for (i = 0;i < r_refdef.scene.numentities;i++)
4850 ent = r_refdef.scene.entities[i];
4852 // cast shadows from anything of the map (submodels are optional)
4853 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4855 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4856 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4857 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4858 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4859 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4860 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4861 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4862 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4863 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4864 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4865 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4866 RSurf_ActiveModelEntity(ent, false, false, false);
4867 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4868 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4875 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4877 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4879 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4880 Cvar_SetValueQuick(&r_test, 0);
4885 R_Shadow_RenderMode_End();
4887 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4888 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4889 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4890 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4891 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4892 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4894 switch (vid.renderpath)
4896 case RENDERPATH_GL11:
4897 case RENDERPATH_GL13:
4898 case RENDERPATH_GL20:
4899 case RENDERPATH_SOFT:
4900 case RENDERPATH_GLES1:
4901 case RENDERPATH_GLES2:
4903 case RENDERPATH_D3D9:
4904 case RENDERPATH_D3D10:
4905 case RENDERPATH_D3D11:
4906 #ifdef OPENGL_ORIENTATION
4907 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4908 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
4909 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
4910 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
4912 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4913 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
4914 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
4915 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
4920 r_shadow_usingshadowmaportho = true;
4921 switch (r_shadow_shadowmode)
4923 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4924 r_shadow_usingshadowmap2d = true;
4931 void R_DrawModelShadows(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
4934 float relativethrowdistance;
4935 entity_render_t *ent;
4936 vec3_t relativelightorigin;
4937 vec3_t relativelightdirection;
4938 vec3_t relativeshadowmins, relativeshadowmaxs;
4939 vec3_t tmp, shadowdir;
4941 if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4944 r_shadow_fb_fbo = fbo;
4945 r_shadow_fb_depthtexture = depthtexture;
4946 r_shadow_fb_colortexture = colortexture;
4948 R_ResetViewRendering3D(fbo, depthtexture, colortexture);
4949 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4950 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4951 R_Shadow_RenderMode_Begin();
4952 R_Shadow_RenderMode_ActiveLight(NULL);
4953 r_shadow_lightscissor[0] = r_refdef.view.x;
4954 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4955 r_shadow_lightscissor[2] = r_refdef.view.width;
4956 r_shadow_lightscissor[3] = r_refdef.view.height;
4957 R_Shadow_RenderMode_StencilShadowVolumes(false);
4960 if (r_shadows.integer == 2)
4962 Math_atov(r_shadows_throwdirection.string, shadowdir);
4963 VectorNormalize(shadowdir);
4966 R_Shadow_ClearStencil();
4968 for (i = 0;i < r_refdef.scene.numentities;i++)
4970 ent = r_refdef.scene.entities[i];
4972 // cast shadows from anything of the map (submodels are optional)
4973 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4975 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4976 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4977 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4978 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4979 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4982 if(ent->entitynumber != 0)
4984 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4986 // FIXME handle this
4987 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4991 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4992 int entnum, entnum2, recursion;
4993 entnum = entnum2 = ent->entitynumber;
4994 for(recursion = 32; recursion > 0; --recursion)
4996 entnum2 = cl.entities[entnum].state_current.tagentity;
4997 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
5002 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
5004 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
5005 // transform into modelspace of OUR entity
5006 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
5007 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
5010 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5014 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5017 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
5018 RSurf_ActiveModelEntity(ent, false, false, false);
5019 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
5020 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5024 // not really the right mode, but this will disable any silly stencil features
5025 R_Shadow_RenderMode_End();
5027 // set up ortho view for rendering this pass
5028 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5029 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5030 //GL_ScissorTest(true);
5031 //R_EntityMatrix(&identitymatrix);
5032 //R_Mesh_ResetTextureState();
5033 R_ResetViewRendering2D(fbo, depthtexture, colortexture);
5035 // set up a darkening blend on shadowed areas
5036 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5037 //GL_DepthRange(0, 1);
5038 //GL_DepthTest(false);
5039 //GL_DepthMask(false);
5040 //GL_PolygonOffset(0, 0);CHECKGLERROR
5041 GL_Color(0, 0, 0, r_shadows_darken.value);
5042 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5043 //GL_DepthFunc(GL_ALWAYS);
5044 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5046 // apply the blend to the shadowed areas
5047 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5048 R_SetupShader_Generic_NoTexture(false, true);
5049 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5051 // restore the viewport
5052 R_SetViewport(&r_refdef.view.viewport);
5054 // restore other state to normal
5055 //R_Shadow_RenderMode_End();
5058 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5061 vec3_t centerorigin;
5063 // if it's too close, skip it
5064 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5066 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5069 if (usequery && r_numqueries + 2 <= r_maxqueries)
5071 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5072 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5073 // 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
5074 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5076 switch(vid.renderpath)
5078 case RENDERPATH_GL11:
5079 case RENDERPATH_GL13:
5080 case RENDERPATH_GL20:
5081 case RENDERPATH_GLES1:
5082 case RENDERPATH_GLES2:
5083 #ifdef GL_SAMPLES_PASSED_ARB
5085 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5086 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5087 GL_DepthFunc(GL_ALWAYS);
5088 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5089 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
5090 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5091 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5092 GL_DepthFunc(GL_LEQUAL);
5093 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5094 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5095 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
5096 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5097 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5101 case RENDERPATH_D3D9:
5102 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5104 case RENDERPATH_D3D10:
5105 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5107 case RENDERPATH_D3D11:
5108 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5110 case RENDERPATH_SOFT:
5111 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5115 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5118 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5120 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5123 GLint allpixels = 0, visiblepixels = 0;
5124 // now we have to check the query result
5125 if (rtlight->corona_queryindex_visiblepixels)
5127 switch(vid.renderpath)
5129 case RENDERPATH_GL11:
5130 case RENDERPATH_GL13:
5131 case RENDERPATH_GL20:
5132 case RENDERPATH_GLES1:
5133 case RENDERPATH_GLES2:
5134 #ifdef GL_SAMPLES_PASSED_ARB
5136 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5137 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5141 case RENDERPATH_D3D9:
5142 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5144 case RENDERPATH_D3D10:
5145 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5147 case RENDERPATH_D3D11:
5148 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5150 case RENDERPATH_SOFT:
5151 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5154 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
5155 if (visiblepixels < 1 || allpixels < 1)
5157 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5158 cscale *= rtlight->corona_visibility;
5162 // FIXME: these traces should scan all render entities instead of cl.world
5163 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1)
5166 VectorScale(rtlight->currentcolor, cscale, color);
5167 if (VectorLength(color) > (1.0f / 256.0f))
5170 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
5173 VectorNegate(color, color);
5174 GL_BlendEquationSubtract(true);
5176 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5177 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);
5178 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5180 GL_BlendEquationSubtract(false);
5184 void R_Shadow_DrawCoronas(void)
5187 qboolean usequery = false;
5192 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
5194 if (r_fb.water.renderingscene)
5196 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5197 R_EntityMatrix(&identitymatrix);
5199 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5201 // check occlusion of coronas
5202 // use GL_ARB_occlusion_query if available
5203 // otherwise use raytraces
5205 switch (vid.renderpath)
5207 case RENDERPATH_GL11:
5208 case RENDERPATH_GL13:
5209 case RENDERPATH_GL20:
5210 case RENDERPATH_GLES1:
5211 case RENDERPATH_GLES2:
5212 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
5213 #ifdef GL_SAMPLES_PASSED_ARB
5216 GL_ColorMask(0,0,0,0);
5217 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
5218 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
5221 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
5222 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
5224 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
5227 RSurf_ActiveWorldEntity();
5228 GL_BlendFunc(GL_ONE, GL_ZERO);
5229 GL_CullFace(GL_NONE);
5230 GL_DepthMask(false);
5231 GL_DepthRange(0, 1);
5232 GL_PolygonOffset(0, 0);
5234 R_Mesh_ResetTextureState();
5235 R_SetupShader_Generic_NoTexture(false, false);
5239 case RENDERPATH_D3D9:
5241 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5243 case RENDERPATH_D3D10:
5244 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5246 case RENDERPATH_D3D11:
5247 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5249 case RENDERPATH_SOFT:
5251 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5254 for (lightindex = 0;lightindex < range;lightindex++)
5256 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5259 rtlight = &light->rtlight;
5260 rtlight->corona_visibility = 0;
5261 rtlight->corona_queryindex_visiblepixels = 0;
5262 rtlight->corona_queryindex_allpixels = 0;
5263 if (!(rtlight->flags & flag))
5265 if (rtlight->corona <= 0)
5267 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
5269 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5271 for (i = 0;i < r_refdef.scene.numlights;i++)
5273 rtlight = r_refdef.scene.lights[i];
5274 rtlight->corona_visibility = 0;
5275 rtlight->corona_queryindex_visiblepixels = 0;
5276 rtlight->corona_queryindex_allpixels = 0;
5277 if (!(rtlight->flags & flag))
5279 if (rtlight->corona <= 0)
5281 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5284 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5286 // now draw the coronas using the query data for intensity info
5287 for (lightindex = 0;lightindex < range;lightindex++)
5289 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5292 rtlight = &light->rtlight;
5293 if (rtlight->corona_visibility <= 0)
5295 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5297 for (i = 0;i < r_refdef.scene.numlights;i++)
5299 rtlight = r_refdef.scene.lights[i];
5300 if (rtlight->corona_visibility <= 0)
5302 if (gl_flashblend.integer)
5303 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
5305 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5311 static dlight_t *R_Shadow_NewWorldLight(void)
5313 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
5316 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)
5319 // validate parameters
5320 if (style < 0 || style >= MAX_LIGHTSTYLES)
5322 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
5328 // copy to light properties
5329 VectorCopy(origin, light->origin);
5330 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
5331 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
5332 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
5334 light->color[0] = max(color[0], 0);
5335 light->color[1] = max(color[1], 0);
5336 light->color[2] = max(color[2], 0);
5338 light->color[0] = color[0];
5339 light->color[1] = color[1];
5340 light->color[2] = color[2];
5341 light->radius = max(radius, 0);
5342 light->style = style;
5343 light->shadow = shadowenable;
5344 light->corona = corona;
5345 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
5346 light->coronasizescale = coronasizescale;
5347 light->ambientscale = ambientscale;
5348 light->diffusescale = diffusescale;
5349 light->specularscale = specularscale;
5350 light->flags = flags;
5352 // update renderable light data
5353 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
5354 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);
5357 static void R_Shadow_FreeWorldLight(dlight_t *light)
5359 if (r_shadow_selectedlight == light)
5360 r_shadow_selectedlight = NULL;
5361 R_RTLight_Uncompile(&light->rtlight);
5362 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
5365 void R_Shadow_ClearWorldLights(void)
5369 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5370 for (lightindex = 0;lightindex < range;lightindex++)
5372 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5374 R_Shadow_FreeWorldLight(light);
5376 r_shadow_selectedlight = NULL;
5379 static void R_Shadow_SelectLight(dlight_t *light)
5381 if (r_shadow_selectedlight)
5382 r_shadow_selectedlight->selected = false;
5383 r_shadow_selectedlight = light;
5384 if (r_shadow_selectedlight)
5385 r_shadow_selectedlight->selected = true;
5388 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5390 // this is never batched (there can be only one)
5392 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
5393 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5394 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5397 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5402 skinframe_t *skinframe;
5405 // this is never batched (due to the ent parameter changing every time)
5406 // so numsurfaces == 1 and surfacelist[0] == lightnumber
5407 const dlight_t *light = (dlight_t *)ent;
5410 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
5413 VectorScale(light->color, intensity, spritecolor);
5414 if (VectorLength(spritecolor) < 0.1732f)
5415 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
5416 if (VectorLength(spritecolor) > 1.0f)
5417 VectorNormalize(spritecolor);
5419 // draw light sprite
5420 if (light->cubemapname[0] && !light->shadow)
5421 skinframe = r_editlights_sprcubemapnoshadowlight;
5422 else if (light->cubemapname[0])
5423 skinframe = r_editlights_sprcubemaplight;
5424 else if (!light->shadow)
5425 skinframe = r_editlights_sprnoshadowlight;
5427 skinframe = r_editlights_sprlight;
5429 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);
5430 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5432 // draw selection sprite if light is selected
5433 if (light->selected)
5435 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5436 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5437 // VorteX todo: add normalmode/realtime mode light overlay sprites?
5441 void R_Shadow_DrawLightSprites(void)
5445 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5446 for (lightindex = 0;lightindex < range;lightindex++)
5448 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5450 R_MeshQueue_AddTransparent(MESHQUEUE_SORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
5452 if (!r_editlights_lockcursor)
5453 R_MeshQueue_AddTransparent(MESHQUEUE_SORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
5456 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
5461 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
5462 if (lightindex >= range)
5464 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5467 rtlight = &light->rtlight;
5468 //if (!(rtlight->flags & flag))
5470 VectorCopy(rtlight->shadoworigin, origin);
5471 *radius = rtlight->radius;
5472 VectorCopy(rtlight->color, color);
5476 static void R_Shadow_SelectLightInView(void)
5478 float bestrating, rating, temp[3];
5482 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5486 if (r_editlights_lockcursor)
5488 for (lightindex = 0;lightindex < range;lightindex++)
5490 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5493 VectorSubtract(light->origin, r_refdef.view.origin, temp);
5494 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
5497 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
5498 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction == 1.0f)
5500 bestrating = rating;
5505 R_Shadow_SelectLight(best);
5508 void R_Shadow_LoadWorldLights(void)
5510 int n, a, style, shadow, flags;
5511 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
5512 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
5513 if (cl.worldmodel == NULL)
5515 Con_Print("No map loaded.\n");
5518 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5519 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5529 for (;COM_Parse(t, true) && strcmp(
5530 if (COM_Parse(t, true))
5532 if (com_token[0] == '!')
5535 origin[0] = atof(com_token+1);
5538 origin[0] = atof(com_token);
5543 while (*s && *s != '\n' && *s != '\r')
5549 // check for modifier flags
5556 #if _MSC_VER >= 1400
5557 #define sscanf sscanf_s
5559 cubemapname[sizeof(cubemapname)-1] = 0;
5560 #if MAX_QPATH != 128
5561 #error update this code if MAX_QPATH changes
5563 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
5564 #if _MSC_VER >= 1400
5565 , sizeof(cubemapname)
5567 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5570 flags = LIGHTFLAG_REALTIMEMODE;
5578 coronasizescale = 0.25f;
5580 VectorClear(angles);
5583 if (a < 9 || !strcmp(cubemapname, "\"\""))
5585 // remove quotes on cubemapname
5586 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5589 namelen = strlen(cubemapname) - 2;
5590 memmove(cubemapname, cubemapname + 1, namelen);
5591 cubemapname[namelen] = '\0';
5595 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);
5598 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5606 Con_Printf("invalid rtlights file \"%s\"\n", name);
5607 Mem_Free(lightsstring);
5611 void R_Shadow_SaveWorldLights(void)
5615 size_t bufchars, bufmaxchars;
5617 char name[MAX_QPATH];
5618 char line[MAX_INPUTLINE];
5619 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5620 // I hate lines which are 3 times my screen size :( --blub
5623 if (cl.worldmodel == NULL)
5625 Con_Print("No map loaded.\n");
5628 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5629 bufchars = bufmaxchars = 0;
5631 for (lightindex = 0;lightindex < range;lightindex++)
5633 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5636 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5637 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);
5638 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5639 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]);
5641 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);
5642 if (bufchars + strlen(line) > bufmaxchars)
5644 bufmaxchars = bufchars + strlen(line) + 2048;
5646 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5650 memcpy(buf, oldbuf, bufchars);
5656 memcpy(buf + bufchars, line, strlen(line));
5657 bufchars += strlen(line);
5661 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5666 void R_Shadow_LoadLightsFile(void)
5669 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5670 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5671 if (cl.worldmodel == NULL)
5673 Con_Print("No map loaded.\n");
5676 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5677 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5685 while (*s && *s != '\n' && *s != '\r')
5691 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);
5695 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);
5698 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5699 radius = bound(15, radius, 4096);
5700 VectorScale(color, (2.0f / (8388608.0f)), color);
5701 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5709 Con_Printf("invalid lights file \"%s\"\n", name);
5710 Mem_Free(lightsstring);
5714 // tyrlite/hmap2 light types in the delay field
5715 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5717 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5729 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5730 char key[256], value[MAX_INPUTLINE];
5733 if (cl.worldmodel == NULL)
5735 Con_Print("No map loaded.\n");
5738 // try to load a .ent file first
5739 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5740 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5741 // and if that is not found, fall back to the bsp file entity string
5743 data = cl.worldmodel->brush.entities;
5746 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
5748 type = LIGHTTYPE_MINUSX;
5749 origin[0] = origin[1] = origin[2] = 0;
5750 originhack[0] = originhack[1] = originhack[2] = 0;
5751 angles[0] = angles[1] = angles[2] = 0;
5752 color[0] = color[1] = color[2] = 1;
5753 light[0] = light[1] = light[2] = 1;light[3] = 300;
5754 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5764 if (!COM_ParseToken_Simple(&data, false, false, true))
5766 if (com_token[0] == '}')
5767 break; // end of entity
5768 if (com_token[0] == '_')
5769 strlcpy(key, com_token + 1, sizeof(key));
5771 strlcpy(key, com_token, sizeof(key));
5772 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5773 key[strlen(key)-1] = 0;
5774 if (!COM_ParseToken_Simple(&data, false, false, true))
5776 strlcpy(value, com_token, sizeof(value));
5778 // now that we have the key pair worked out...
5779 if (!strcmp("light", key))
5781 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5785 light[0] = vec[0] * (1.0f / 256.0f);
5786 light[1] = vec[0] * (1.0f / 256.0f);
5787 light[2] = vec[0] * (1.0f / 256.0f);
5793 light[0] = vec[0] * (1.0f / 255.0f);
5794 light[1] = vec[1] * (1.0f / 255.0f);
5795 light[2] = vec[2] * (1.0f / 255.0f);
5799 else if (!strcmp("delay", key))
5801 else if (!strcmp("origin", key))
5802 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5803 else if (!strcmp("angle", key))
5804 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5805 else if (!strcmp("angles", key))
5806 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5807 else if (!strcmp("color", key))
5808 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5809 else if (!strcmp("wait", key))
5810 fadescale = atof(value);
5811 else if (!strcmp("classname", key))
5813 if (!strncmp(value, "light", 5))
5816 if (!strcmp(value, "light_fluoro"))
5821 overridecolor[0] = 1;
5822 overridecolor[1] = 1;
5823 overridecolor[2] = 1;
5825 if (!strcmp(value, "light_fluorospark"))
5830 overridecolor[0] = 1;
5831 overridecolor[1] = 1;
5832 overridecolor[2] = 1;
5834 if (!strcmp(value, "light_globe"))
5839 overridecolor[0] = 1;
5840 overridecolor[1] = 0.8;
5841 overridecolor[2] = 0.4;
5843 if (!strcmp(value, "light_flame_large_yellow"))
5848 overridecolor[0] = 1;
5849 overridecolor[1] = 0.5;
5850 overridecolor[2] = 0.1;
5852 if (!strcmp(value, "light_flame_small_yellow"))
5857 overridecolor[0] = 1;
5858 overridecolor[1] = 0.5;
5859 overridecolor[2] = 0.1;
5861 if (!strcmp(value, "light_torch_small_white"))
5866 overridecolor[0] = 1;
5867 overridecolor[1] = 0.5;
5868 overridecolor[2] = 0.1;
5870 if (!strcmp(value, "light_torch_small_walltorch"))
5875 overridecolor[0] = 1;
5876 overridecolor[1] = 0.5;
5877 overridecolor[2] = 0.1;
5881 else if (!strcmp("style", key))
5882 style = atoi(value);
5883 else if (!strcmp("skin", key))
5884 skin = (int)atof(value);
5885 else if (!strcmp("pflags", key))
5886 pflags = (int)atof(value);
5887 //else if (!strcmp("effects", key))
5888 // effects = (int)atof(value);
5889 else if (cl.worldmodel->type == mod_brushq3)
5891 if (!strcmp("scale", key))
5892 lightscale = atof(value);
5893 if (!strcmp("fade", key))
5894 fadescale = atof(value);
5899 if (lightscale <= 0)
5903 if (color[0] == color[1] && color[0] == color[2])
5905 color[0] *= overridecolor[0];
5906 color[1] *= overridecolor[1];
5907 color[2] *= overridecolor[2];
5909 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5910 color[0] = color[0] * light[0];
5911 color[1] = color[1] * light[1];
5912 color[2] = color[2] * light[2];
5915 case LIGHTTYPE_MINUSX:
5917 case LIGHTTYPE_RECIPX:
5919 VectorScale(color, (1.0f / 16.0f), color);
5921 case LIGHTTYPE_RECIPXX:
5923 VectorScale(color, (1.0f / 16.0f), color);
5926 case LIGHTTYPE_NONE:
5930 case LIGHTTYPE_MINUSXX:
5933 VectorAdd(origin, originhack, origin);
5935 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);
5938 Mem_Free(entfiledata);
5942 static void R_Shadow_SetCursorLocationForView(void)
5945 vec3_t dest, endpos;
5947 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5948 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true);
5949 if (trace.fraction < 1)
5951 dist = trace.fraction * r_editlights_cursordistance.value;
5952 push = r_editlights_cursorpushback.value;
5956 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5957 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5961 VectorClear( endpos );
5963 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5964 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5965 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5968 void R_Shadow_UpdateWorldLightSelection(void)
5970 if (r_editlights.integer)
5972 R_Shadow_SetCursorLocationForView();
5973 R_Shadow_SelectLightInView();
5976 R_Shadow_SelectLight(NULL);
5979 static void R_Shadow_EditLights_Clear_f(void)
5981 R_Shadow_ClearWorldLights();
5984 void R_Shadow_EditLights_Reload_f(void)
5988 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5989 R_Shadow_ClearWorldLights();
5990 R_Shadow_LoadWorldLights();
5991 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5993 R_Shadow_LoadLightsFile();
5994 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5995 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5999 static void R_Shadow_EditLights_Save_f(void)
6003 R_Shadow_SaveWorldLights();
6006 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6008 R_Shadow_ClearWorldLights();
6009 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6012 static void R_Shadow_EditLights_ImportLightsFile_f(void)
6014 R_Shadow_ClearWorldLights();
6015 R_Shadow_LoadLightsFile();
6018 static void R_Shadow_EditLights_Spawn_f(void)
6021 if (!r_editlights.integer)
6023 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6026 if (Cmd_Argc() != 1)
6028 Con_Print("r_editlights_spawn does not take parameters\n");
6031 color[0] = color[1] = color[2] = 1;
6032 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6035 static void R_Shadow_EditLights_Edit_f(void)
6037 vec3_t origin, angles, color;
6038 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6039 int style, shadows, flags, normalmode, realtimemode;
6040 char cubemapname[MAX_INPUTLINE];
6041 if (!r_editlights.integer)
6043 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6046 if (!r_shadow_selectedlight)
6048 Con_Print("No selected light.\n");
6051 VectorCopy(r_shadow_selectedlight->origin, origin);
6052 VectorCopy(r_shadow_selectedlight->angles, angles);
6053 VectorCopy(r_shadow_selectedlight->color, color);
6054 radius = r_shadow_selectedlight->radius;
6055 style = r_shadow_selectedlight->style;
6056 if (r_shadow_selectedlight->cubemapname)
6057 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6060 shadows = r_shadow_selectedlight->shadow;
6061 corona = r_shadow_selectedlight->corona;
6062 coronasizescale = r_shadow_selectedlight->coronasizescale;
6063 ambientscale = r_shadow_selectedlight->ambientscale;
6064 diffusescale = r_shadow_selectedlight->diffusescale;
6065 specularscale = r_shadow_selectedlight->specularscale;
6066 flags = r_shadow_selectedlight->flags;
6067 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6068 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6069 if (!strcmp(Cmd_Argv(1), "origin"))
6071 if (Cmd_Argc() != 5)
6073 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6076 origin[0] = atof(Cmd_Argv(2));
6077 origin[1] = atof(Cmd_Argv(3));
6078 origin[2] = atof(Cmd_Argv(4));
6080 else if (!strcmp(Cmd_Argv(1), "originscale"))
6082 if (Cmd_Argc() != 5)
6084 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6087 origin[0] *= atof(Cmd_Argv(2));
6088 origin[1] *= atof(Cmd_Argv(3));
6089 origin[2] *= atof(Cmd_Argv(4));
6091 else if (!strcmp(Cmd_Argv(1), "originx"))
6093 if (Cmd_Argc() != 3)
6095 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6098 origin[0] = atof(Cmd_Argv(2));
6100 else if (!strcmp(Cmd_Argv(1), "originy"))
6102 if (Cmd_Argc() != 3)
6104 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6107 origin[1] = atof(Cmd_Argv(2));
6109 else if (!strcmp(Cmd_Argv(1), "originz"))
6111 if (Cmd_Argc() != 3)
6113 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6116 origin[2] = atof(Cmd_Argv(2));
6118 else if (!strcmp(Cmd_Argv(1), "move"))
6120 if (Cmd_Argc() != 5)
6122 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6125 origin[0] += atof(Cmd_Argv(2));
6126 origin[1] += atof(Cmd_Argv(3));
6127 origin[2] += atof(Cmd_Argv(4));
6129 else if (!strcmp(Cmd_Argv(1), "movex"))
6131 if (Cmd_Argc() != 3)
6133 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6136 origin[0] += atof(Cmd_Argv(2));
6138 else if (!strcmp(Cmd_Argv(1), "movey"))
6140 if (Cmd_Argc() != 3)
6142 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6145 origin[1] += atof(Cmd_Argv(2));
6147 else if (!strcmp(Cmd_Argv(1), "movez"))
6149 if (Cmd_Argc() != 3)
6151 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6154 origin[2] += atof(Cmd_Argv(2));
6156 else if (!strcmp(Cmd_Argv(1), "angles"))
6158 if (Cmd_Argc() != 5)
6160 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6163 angles[0] = atof(Cmd_Argv(2));
6164 angles[1] = atof(Cmd_Argv(3));
6165 angles[2] = atof(Cmd_Argv(4));
6167 else if (!strcmp(Cmd_Argv(1), "anglesx"))
6169 if (Cmd_Argc() != 3)
6171 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6174 angles[0] = atof(Cmd_Argv(2));
6176 else if (!strcmp(Cmd_Argv(1), "anglesy"))
6178 if (Cmd_Argc() != 3)
6180 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6183 angles[1] = atof(Cmd_Argv(2));
6185 else if (!strcmp(Cmd_Argv(1), "anglesz"))
6187 if (Cmd_Argc() != 3)
6189 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6192 angles[2] = atof(Cmd_Argv(2));
6194 else if (!strcmp(Cmd_Argv(1), "color"))
6196 if (Cmd_Argc() != 5)
6198 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
6201 color[0] = atof(Cmd_Argv(2));
6202 color[1] = atof(Cmd_Argv(3));
6203 color[2] = atof(Cmd_Argv(4));
6205 else if (!strcmp(Cmd_Argv(1), "radius"))
6207 if (Cmd_Argc() != 3)
6209 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6212 radius = atof(Cmd_Argv(2));
6214 else if (!strcmp(Cmd_Argv(1), "colorscale"))
6216 if (Cmd_Argc() == 3)
6218 double scale = atof(Cmd_Argv(2));
6225 if (Cmd_Argc() != 5)
6227 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
6230 color[0] *= atof(Cmd_Argv(2));
6231 color[1] *= atof(Cmd_Argv(3));
6232 color[2] *= atof(Cmd_Argv(4));
6235 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
6237 if (Cmd_Argc() != 3)
6239 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6242 radius *= atof(Cmd_Argv(2));
6244 else if (!strcmp(Cmd_Argv(1), "style"))
6246 if (Cmd_Argc() != 3)
6248 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6251 style = atoi(Cmd_Argv(2));
6253 else if (!strcmp(Cmd_Argv(1), "cubemap"))
6257 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6260 if (Cmd_Argc() == 3)
6261 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
6265 else if (!strcmp(Cmd_Argv(1), "shadows"))
6267 if (Cmd_Argc() != 3)
6269 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6272 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6274 else if (!strcmp(Cmd_Argv(1), "corona"))
6276 if (Cmd_Argc() != 3)
6278 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6281 corona = atof(Cmd_Argv(2));
6283 else if (!strcmp(Cmd_Argv(1), "coronasize"))
6285 if (Cmd_Argc() != 3)
6287 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6290 coronasizescale = atof(Cmd_Argv(2));
6292 else if (!strcmp(Cmd_Argv(1), "ambient"))
6294 if (Cmd_Argc() != 3)
6296 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6299 ambientscale = atof(Cmd_Argv(2));
6301 else if (!strcmp(Cmd_Argv(1), "diffuse"))
6303 if (Cmd_Argc() != 3)
6305 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6308 diffusescale = atof(Cmd_Argv(2));
6310 else if (!strcmp(Cmd_Argv(1), "specular"))
6312 if (Cmd_Argc() != 3)
6314 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6317 specularscale = atof(Cmd_Argv(2));
6319 else if (!strcmp(Cmd_Argv(1), "normalmode"))
6321 if (Cmd_Argc() != 3)
6323 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6326 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6328 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
6330 if (Cmd_Argc() != 3)
6332 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6335 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6339 Con_Print("usage: r_editlights_edit [property] [value]\n");
6340 Con_Print("Selected light's properties:\n");
6341 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6342 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6343 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6344 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
6345 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
6346 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
6347 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
6348 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
6349 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
6350 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
6351 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
6352 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
6353 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
6354 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
6357 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
6358 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6361 static void R_Shadow_EditLights_EditAll_f(void)
6364 dlight_t *light, *oldselected;
6367 if (!r_editlights.integer)
6369 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
6373 oldselected = r_shadow_selectedlight;
6374 // EditLights doesn't seem to have a "remove" command or something so:
6375 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6376 for (lightindex = 0;lightindex < range;lightindex++)
6378 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6381 R_Shadow_SelectLight(light);
6382 R_Shadow_EditLights_Edit_f();
6384 // return to old selected (to not mess editing once selection is locked)
6385 R_Shadow_SelectLight(oldselected);
6388 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
6390 int lightnumber, lightcount;
6391 size_t lightindex, range;
6395 if (!r_editlights.integer)
6397 x = vid_conwidth.value - 240;
6399 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
6402 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6403 for (lightindex = 0;lightindex < range;lightindex++)
6405 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6408 if (light == r_shadow_selectedlight)
6409 lightnumber = lightindex;
6412 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;
6413 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;
6415 if (r_shadow_selectedlight == NULL)
6417 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;
6418 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;
6419 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;
6420 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;
6421 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;
6422 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;
6423 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;
6424 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;
6425 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;
6426 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;
6427 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;
6428 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;
6429 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;
6430 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;
6431 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;
6434 static void R_Shadow_EditLights_ToggleShadow_f(void)
6436 if (!r_editlights.integer)
6438 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6441 if (!r_shadow_selectedlight)
6443 Con_Print("No selected light.\n");
6446 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);
6449 static void R_Shadow_EditLights_ToggleCorona_f(void)
6451 if (!r_editlights.integer)
6453 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6456 if (!r_shadow_selectedlight)
6458 Con_Print("No selected light.\n");
6461 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);
6464 static void R_Shadow_EditLights_Remove_f(void)
6466 if (!r_editlights.integer)
6468 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
6471 if (!r_shadow_selectedlight)
6473 Con_Print("No selected light.\n");
6476 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
6477 r_shadow_selectedlight = NULL;
6480 static void R_Shadow_EditLights_Help_f(void)
6483 "Documentation on r_editlights system:\n"
6485 "r_editlights : enable/disable editing mode\n"
6486 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
6487 "r_editlights_cursorpushback : push back cursor this far from surface\n"
6488 "r_editlights_cursorpushoff : push cursor off surface this far\n"
6489 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
6490 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
6492 "r_editlights_help : this help\n"
6493 "r_editlights_clear : remove all lights\n"
6494 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
6495 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
6496 "r_editlights_save : save to .rtlights file\n"
6497 "r_editlights_spawn : create a light with default settings\n"
6498 "r_editlights_edit command : edit selected light - more documentation below\n"
6499 "r_editlights_remove : remove selected light\n"
6500 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
6501 "r_editlights_importlightentitiesfrommap : reload light entities\n"
6502 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
6504 "origin x y z : set light location\n"
6505 "originx x: set x component of light location\n"
6506 "originy y: set y component of light location\n"
6507 "originz z: set z component of light location\n"
6508 "move x y z : adjust light location\n"
6509 "movex x: adjust x component of light location\n"
6510 "movey y: adjust y component of light location\n"
6511 "movez z: adjust z component of light location\n"
6512 "angles x y z : set light angles\n"
6513 "anglesx x: set x component of light angles\n"
6514 "anglesy y: set y component of light angles\n"
6515 "anglesz z: set z component of light angles\n"
6516 "color r g b : set color of light (can be brighter than 1 1 1)\n"
6517 "radius radius : set radius (size) of light\n"
6518 "colorscale grey : multiply color of light (1 does nothing)\n"
6519 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
6520 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
6521 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
6522 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
6523 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
6524 "cubemap basename : set filter cubemap of light (not yet supported)\n"
6525 "shadows 1/0 : turn on/off shadows\n"
6526 "corona n : set corona intensity\n"
6527 "coronasize n : set corona size (0-1)\n"
6528 "ambient n : set ambient intensity (0-1)\n"
6529 "diffuse n : set diffuse intensity (0-1)\n"
6530 "specular n : set specular intensity (0-1)\n"
6531 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6532 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6533 "<nothing> : print light properties to console\n"
6537 static void R_Shadow_EditLights_CopyInfo_f(void)
6539 if (!r_editlights.integer)
6541 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
6544 if (!r_shadow_selectedlight)
6546 Con_Print("No selected light.\n");
6549 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6550 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6551 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6552 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6553 if (r_shadow_selectedlight->cubemapname)
6554 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6556 r_shadow_bufferlight.cubemapname[0] = 0;
6557 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6558 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6559 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6560 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6561 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6562 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6563 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6566 static void R_Shadow_EditLights_PasteInfo_f(void)
6568 if (!r_editlights.integer)
6570 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6573 if (!r_shadow_selectedlight)
6575 Con_Print("No selected light.\n");
6578 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);
6581 static void R_Shadow_EditLights_Lock_f(void)
6583 if (!r_editlights.integer)
6585 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6588 if (r_editlights_lockcursor)
6590 r_editlights_lockcursor = false;
6593 if (!r_shadow_selectedlight)
6595 Con_Print("No selected light to lock on.\n");
6598 r_editlights_lockcursor = true;
6601 static void R_Shadow_EditLights_Init(void)
6603 Cvar_RegisterVariable(&r_editlights);
6604 Cvar_RegisterVariable(&r_editlights_cursordistance);
6605 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6606 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6607 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6608 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6609 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6610 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6611 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)");
6612 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6613 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6614 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6615 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)");
6616 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6617 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6618 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6619 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6620 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6621 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6622 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)");
6623 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6629 =============================================================================
6633 =============================================================================
6636 void R_LightPoint(vec3_t color, const vec3_t p, const int flags)
6638 int i, numlights, flag;
6639 float f, relativepoint[3], dist, dist2, lightradius2;
6644 if (r_fullbright.integer)
6646 VectorSet(color, 1, 1, 1);
6652 if (flags & LP_LIGHTMAP)
6654 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6656 VectorClear(diffuse);
6657 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, color, diffuse, n);
6658 VectorAdd(color, diffuse, color);
6661 VectorSet(color, 1, 1, 1);
6662 color[0] += r_refdef.scene.ambient;
6663 color[1] += r_refdef.scene.ambient;
6664 color[2] += r_refdef.scene.ambient;
6667 if (flags & LP_RTWORLD)
6669 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6670 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6671 for (i = 0; i < numlights; i++)
6673 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6676 light = &dlight->rtlight;
6677 if (!(light->flags & flag))
6680 lightradius2 = light->radius * light->radius;
6681 VectorSubtract(light->shadoworigin, p, relativepoint);
6682 dist2 = VectorLength2(relativepoint);
6683 if (dist2 >= lightradius2)
6685 dist = sqrt(dist2) / light->radius;
6686 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
6689 // todo: add to both ambient and diffuse
6690 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction == 1)
6691 VectorMA(color, f, light->currentcolor, color);
6694 if (flags & LP_DYNLIGHT)
6697 for (i = 0;i < r_refdef.scene.numlights;i++)
6699 light = r_refdef.scene.lights[i];
6701 lightradius2 = light->radius * light->radius;
6702 VectorSubtract(light->shadoworigin, p, relativepoint);
6703 dist2 = VectorLength2(relativepoint);
6704 if (dist2 >= lightradius2)
6706 dist = sqrt(dist2) / light->radius;
6707 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
6710 // todo: add to both ambient and diffuse
6711 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction == 1)
6712 VectorMA(color, f, light->color, color);
6717 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
6719 int i, numlights, flag;
6722 float relativepoint[3];
6731 if (r_fullbright.integer)
6733 VectorSet(ambient, 1, 1, 1);
6734 VectorClear(diffuse);
6735 VectorClear(lightdir);
6739 if (flags == LP_LIGHTMAP)
6741 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6742 VectorClear(diffuse);
6743 VectorClear(lightdir);
6744 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6745 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
6747 VectorSet(ambient, 1, 1, 1);
6751 memset(sample, 0, sizeof(sample));
6752 VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6754 if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6757 VectorClear(tempambient);
6759 VectorClear(relativepoint);
6760 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6761 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
6762 VectorScale(color, r_refdef.lightmapintensity, color);
6763 VectorAdd(sample, tempambient, sample);
6764 VectorMA(sample , 0.5f , color, sample );
6765 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6766 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6767 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6768 // calculate a weighted average light direction as well
6769 intensity = VectorLength(color);
6770 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6773 if (flags & LP_RTWORLD)
6775 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6776 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6777 for (i = 0; i < numlights; i++)
6779 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6782 light = &dlight->rtlight;
6783 if (!(light->flags & flag))
6786 lightradius2 = light->radius * light->radius;
6787 VectorSubtract(light->shadoworigin, p, relativepoint);
6788 dist2 = VectorLength2(relativepoint);
6789 if (dist2 >= lightradius2)
6791 dist = sqrt(dist2) / light->radius;
6792 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6793 if (intensity <= 0.0f)
6795 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1)
6797 // scale down intensity to add to both ambient and diffuse
6798 //intensity *= 0.5f;
6799 VectorNormalize(relativepoint);
6800 VectorScale(light->currentcolor, intensity, color);
6801 VectorMA(sample , 0.5f , color, sample );
6802 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6803 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6804 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6805 // calculate a weighted average light direction as well
6806 intensity *= VectorLength(color);
6807 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6809 // FIXME: sample bouncegrid too!
6812 if (flags & LP_DYNLIGHT)
6815 for (i = 0;i < r_refdef.scene.numlights;i++)
6817 light = r_refdef.scene.lights[i];
6819 lightradius2 = light->radius * light->radius;
6820 VectorSubtract(light->shadoworigin, p, relativepoint);
6821 dist2 = VectorLength2(relativepoint);
6822 if (dist2 >= lightradius2)
6824 dist = sqrt(dist2) / light->radius;
6825 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6826 if (intensity <= 0.0f)
6828 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1)
6830 // scale down intensity to add to both ambient and diffuse
6831 //intensity *= 0.5f;
6832 VectorNormalize(relativepoint);
6833 VectorScale(light->currentcolor, intensity, color);
6834 VectorMA(sample , 0.5f , color, sample );
6835 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6836 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6837 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6838 // calculate a weighted average light direction as well
6839 intensity *= VectorLength(color);
6840 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6844 // calculate the direction we'll use to reduce the sample to a directional light source
6845 VectorCopy(sample + 12, dir);
6846 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
6847 VectorNormalize(dir);
6848 // extract the diffuse color along the chosen direction and scale it
6849 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
6850 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
6851 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
6852 // subtract some of diffuse from ambient
6853 VectorMA(sample, -0.333f, diffuse, ambient);
6854 // store the normalized lightdir
6855 VectorCopy(dir, lightdir);