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 extern 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 int r_shadow_shadowmappcf;
200 int r_shadow_shadowmapborder;
201 matrix4x4_t r_shadow_shadowmapmatrix;
202 int r_shadow_lightscissor[4];
203 qboolean r_shadow_usingdeferredprepass;
205 int maxshadowtriangles;
208 int maxshadowvertices;
209 float *shadowvertex3f;
219 unsigned char *shadowsides;
220 int *shadowsideslist;
227 int r_shadow_buffer_numleafpvsbytes;
228 unsigned char *r_shadow_buffer_visitingleafpvs;
229 unsigned char *r_shadow_buffer_leafpvs;
230 int *r_shadow_buffer_leaflist;
232 int r_shadow_buffer_numsurfacepvsbytes;
233 unsigned char *r_shadow_buffer_surfacepvs;
234 int *r_shadow_buffer_surfacelist;
235 unsigned char *r_shadow_buffer_surfacesides;
237 int r_shadow_buffer_numshadowtrispvsbytes;
238 unsigned char *r_shadow_buffer_shadowtrispvs;
239 int r_shadow_buffer_numlighttrispvsbytes;
240 unsigned char *r_shadow_buffer_lighttrispvs;
242 rtexturepool_t *r_shadow_texturepool;
243 rtexture_t *r_shadow_attenuationgradienttexture;
244 rtexture_t *r_shadow_attenuation2dtexture;
245 rtexture_t *r_shadow_attenuation3dtexture;
246 skinframe_t *r_shadow_lightcorona;
247 rtexture_t *r_shadow_shadowmap2dtexture;
248 rtexture_t *r_shadow_shadowmap2dcolortexture;
249 rtexture_t *r_shadow_shadowmapvsdcttexture;
250 int r_shadow_shadowmapsize; // changes for each light based on distance
251 int r_shadow_shadowmaplod; // changes for each light based on distance
253 GLuint r_shadow_prepassgeometryfbo;
254 GLuint r_shadow_prepasslightingdiffusespecularfbo;
255 GLuint r_shadow_prepasslightingdiffusefbo;
256 int r_shadow_prepass_width;
257 int r_shadow_prepass_height;
258 rtexture_t *r_shadow_prepassgeometrydepthtexture;
259 rtexture_t *r_shadow_prepassgeometrydepthcolortexture;
260 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
261 rtexture_t *r_shadow_prepasslightingdiffusetexture;
262 rtexture_t *r_shadow_prepasslightingspeculartexture;
264 // lights are reloaded when this changes
265 char r_shadow_mapname[MAX_QPATH];
267 // used only for light filters (cubemaps)
268 rtexturepool_t *r_shadow_filters_texturepool;
270 static const GLenum r_shadow_prepasslightingdrawbuffers[2] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
272 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"};
273 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"};
274 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
275 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"};
276 cvar_t r_shadow_deferred_8bitrange = {CVAR_SAVE, "r_shadow_deferred_8bitrange", "2", "dynamic range of image-based lighting when using 32bit color (does not apply to fp)"};
277 //cvar_t r_shadow_deferred_fp = {CVAR_SAVE, "r_shadow_deferred_fp", "0", "use 16bit (1) or 32bit (2) floating point for accumulation of image-based lighting"};
278 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)"};
279 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
280 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)"};
281 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"};
282 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
283 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
284 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
285 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
286 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
287 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
288 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
289 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
290 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
291 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)"};
292 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
293 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
294 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
295 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
296 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)"};
297 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"};
298 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
299 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
300 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"};
301 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)"};
302 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
303 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)"};
304 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"};
305 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)"};
306 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
307 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
308 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
309 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
310 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"};
311 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
312 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
313 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
314 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
315 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
316 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
317 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
318 cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
319 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
320 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)"};
321 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)"};
322 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, requires r_shadow_realtime_world 1"};
323 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"};
324 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"};
325 cvar_t r_shadow_bouncegrid_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
326 cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
327 cvar_t r_shadow_bouncegrid_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_lightradiusscale", "2", "particles stop at this fraction of light radius (can be more than 1)"};
328 cvar_t r_shadow_bouncegrid_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_maxbounce", "3", "maximum number of bounces for a particle (minimum is 1)"};
329 cvar_t r_shadow_bouncegrid_nolerpsplat = {CVAR_SAVE, "r_shadow_bouncegrid_nolerpsplat", "0", "enables slightly quicker (but worse looking) photon accumulation"};
330 cvar_t r_shadow_bouncegrid_particlebounceintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particlebounceintensity", "4", "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"};
331 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "2", "brightness of particles contributing to bouncegrid texture"};
332 cvar_t r_shadow_bouncegrid_photons = {CVAR_SAVE, "r_shadow_bouncegrid_photons", "2000", "total photons to shoot per update, divided proportionately between lights"};
333 cvar_t r_shadow_bouncegrid_spacingx = {CVAR_SAVE, "r_shadow_bouncegrid_spacingx", "64", "unit size of bouncegrid pixel on X axis"};
334 cvar_t r_shadow_bouncegrid_spacingy = {CVAR_SAVE, "r_shadow_bouncegrid_spacingy", "64", "unit size of bouncegrid pixel on Y axis"};
335 cvar_t r_shadow_bouncegrid_spacingz = {CVAR_SAVE, "r_shadow_bouncegrid_spacingz", "64", "unit size of bouncegrid pixel on Z axis"};
336 cvar_t r_shadow_bouncegrid_stablerandom = {CVAR_SAVE, "r_shadow_bouncegrid_stablerandom", "1", "make particle distribution consistent from frame to frame"};
337 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"};
338 cvar_t r_shadow_bouncegrid_x = {CVAR_SAVE, "r_shadow_bouncegrid_x", "64", "maximum texture size of bouncegrid on X axis"};
339 cvar_t r_shadow_bouncegrid_y = {CVAR_SAVE, "r_shadow_bouncegrid_y", "64", "maximum texture size of bouncegrid on Y axis"};
340 cvar_t r_shadow_bouncegrid_z = {CVAR_SAVE, "r_shadow_bouncegrid_z", "32", "maximum texture size of bouncegrid on Z axis"};
341 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
342 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"};
343 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
344 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
345 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
346 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
347 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
348 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
349 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
350 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
351 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
352 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
354 rtexture_t *r_shadow_bouncegridtexture;
355 matrix4x4_t r_shadow_bouncegridmatrix;
356 vec_t r_shadow_bouncegridintensity;
357 static double r_shadow_bouncegridtime;
358 static int r_shadow_bouncegridresolution[3];
359 static int r_shadow_bouncegridnumpixels;
360 static unsigned char *r_shadow_bouncegridpixels;
361 static unsigned short *r_shadow_bouncegridhighpixels;
363 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
364 #define ATTENTABLESIZE 256
365 // 1D gradient, 2D circle and 3D sphere attenuation textures
366 #define ATTEN1DSIZE 32
367 #define ATTEN2DSIZE 64
368 #define ATTEN3DSIZE 32
370 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
371 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
372 static float r_shadow_attentable[ATTENTABLESIZE+1];
374 rtlight_t *r_shadow_compilingrtlight;
375 static memexpandablearray_t r_shadow_worldlightsarray;
376 dlight_t *r_shadow_selectedlight;
377 dlight_t r_shadow_bufferlight;
378 vec3_t r_editlights_cursorlocation;
379 qboolean r_editlights_lockcursor;
381 extern int con_vislines;
383 void R_Shadow_UncompileWorldLights(void);
384 void R_Shadow_ClearWorldLights(void);
385 void R_Shadow_SaveWorldLights(void);
386 void R_Shadow_LoadWorldLights(void);
387 void R_Shadow_LoadLightsFile(void);
388 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
389 void R_Shadow_EditLights_Reload_f(void);
390 void R_Shadow_ValidateCvars(void);
391 static void R_Shadow_MakeTextures(void);
393 #define EDLIGHTSPRSIZE 8
394 skinframe_t *r_editlights_sprcursor;
395 skinframe_t *r_editlights_sprlight;
396 skinframe_t *r_editlights_sprnoshadowlight;
397 skinframe_t *r_editlights_sprcubemaplight;
398 skinframe_t *r_editlights_sprcubemapnoshadowlight;
399 skinframe_t *r_editlights_sprselection;
401 void R_Shadow_SetShadowMode(void)
403 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
404 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
405 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
406 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
407 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
408 r_shadow_shadowmaplod = -1;
409 r_shadow_shadowmapsize = 0;
410 r_shadow_shadowmapsampler = false;
411 r_shadow_shadowmappcf = 0;
412 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
413 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
415 switch(vid.renderpath)
417 case RENDERPATH_GL20:
418 if(r_shadow_shadowmapfilterquality < 0)
420 if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
421 r_shadow_shadowmappcf = 1;
422 else if(strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD"))
424 r_shadow_shadowmapsampler = vid.support.arb_shadow;
425 r_shadow_shadowmappcf = 1;
427 else if(strstr(gl_vendor, "ATI"))
428 r_shadow_shadowmappcf = 1;
430 r_shadow_shadowmapsampler = vid.support.arb_shadow;
434 switch (r_shadow_shadowmapfilterquality)
437 r_shadow_shadowmapsampler = vid.support.arb_shadow;
440 r_shadow_shadowmapsampler = vid.support.arb_shadow;
441 r_shadow_shadowmappcf = 1;
444 r_shadow_shadowmappcf = 1;
447 r_shadow_shadowmappcf = 2;
451 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
453 case RENDERPATH_D3D9:
454 case RENDERPATH_D3D10:
455 case RENDERPATH_D3D11:
456 case RENDERPATH_SOFT:
457 r_shadow_shadowmapsampler = false;
458 r_shadow_shadowmappcf = 1;
459 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
461 case RENDERPATH_GL13:
463 case RENDERPATH_GL11:
465 case RENDERPATH_GLES2:
471 qboolean R_Shadow_ShadowMappingEnabled(void)
473 switch (r_shadow_shadowmode)
475 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
482 void R_Shadow_FreeShadowMaps(void)
484 R_Shadow_SetShadowMode();
486 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
490 if (r_shadow_shadowmap2dtexture)
491 R_FreeTexture(r_shadow_shadowmap2dtexture);
492 r_shadow_shadowmap2dtexture = NULL;
494 if (r_shadow_shadowmap2dcolortexture)
495 R_FreeTexture(r_shadow_shadowmap2dcolortexture);
496 r_shadow_shadowmap2dcolortexture = NULL;
498 if (r_shadow_shadowmapvsdcttexture)
499 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
500 r_shadow_shadowmapvsdcttexture = NULL;
503 void r_shadow_start(void)
505 // allocate vertex processing arrays
506 r_shadow_bouncegridpixels = NULL;
507 r_shadow_bouncegridhighpixels = NULL;
508 r_shadow_bouncegridnumpixels = 0;
509 r_shadow_bouncegridtexture = NULL;
510 r_shadow_attenuationgradienttexture = NULL;
511 r_shadow_attenuation2dtexture = NULL;
512 r_shadow_attenuation3dtexture = NULL;
513 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
514 r_shadow_shadowmap2dtexture = NULL;
515 r_shadow_shadowmap2dcolortexture = NULL;
516 r_shadow_shadowmapvsdcttexture = NULL;
517 r_shadow_shadowmapmaxsize = 0;
518 r_shadow_shadowmapsize = 0;
519 r_shadow_shadowmaplod = 0;
520 r_shadow_shadowmapfilterquality = -1;
521 r_shadow_shadowmapdepthbits = 0;
522 r_shadow_shadowmapvsdct = false;
523 r_shadow_shadowmapsampler = false;
524 r_shadow_shadowmappcf = 0;
527 R_Shadow_FreeShadowMaps();
529 r_shadow_texturepool = NULL;
530 r_shadow_filters_texturepool = NULL;
531 R_Shadow_ValidateCvars();
532 R_Shadow_MakeTextures();
533 maxshadowtriangles = 0;
534 shadowelements = NULL;
535 maxshadowvertices = 0;
536 shadowvertex3f = NULL;
544 shadowmarklist = NULL;
549 shadowsideslist = NULL;
550 r_shadow_buffer_numleafpvsbytes = 0;
551 r_shadow_buffer_visitingleafpvs = NULL;
552 r_shadow_buffer_leafpvs = NULL;
553 r_shadow_buffer_leaflist = NULL;
554 r_shadow_buffer_numsurfacepvsbytes = 0;
555 r_shadow_buffer_surfacepvs = NULL;
556 r_shadow_buffer_surfacelist = NULL;
557 r_shadow_buffer_surfacesides = NULL;
558 r_shadow_buffer_numshadowtrispvsbytes = 0;
559 r_shadow_buffer_shadowtrispvs = NULL;
560 r_shadow_buffer_numlighttrispvsbytes = 0;
561 r_shadow_buffer_lighttrispvs = NULL;
563 r_shadow_usingdeferredprepass = false;
564 r_shadow_prepass_width = r_shadow_prepass_height = 0;
567 static void R_Shadow_FreeDeferred(void);
568 void r_shadow_shutdown(void)
571 R_Shadow_UncompileWorldLights();
573 R_Shadow_FreeShadowMaps();
575 r_shadow_usingdeferredprepass = false;
576 if (r_shadow_prepass_width)
577 R_Shadow_FreeDeferred();
578 r_shadow_prepass_width = r_shadow_prepass_height = 0;
581 r_shadow_bouncegridtexture = NULL;
582 r_shadow_bouncegridpixels = NULL;
583 r_shadow_bouncegridhighpixels = NULL;
584 r_shadow_bouncegridnumpixels = 0;
585 r_shadow_attenuationgradienttexture = NULL;
586 r_shadow_attenuation2dtexture = NULL;
587 r_shadow_attenuation3dtexture = NULL;
588 R_FreeTexturePool(&r_shadow_texturepool);
589 R_FreeTexturePool(&r_shadow_filters_texturepool);
590 maxshadowtriangles = 0;
592 Mem_Free(shadowelements);
593 shadowelements = NULL;
595 Mem_Free(shadowvertex3f);
596 shadowvertex3f = NULL;
599 Mem_Free(vertexupdate);
602 Mem_Free(vertexremap);
608 Mem_Free(shadowmark);
611 Mem_Free(shadowmarklist);
612 shadowmarklist = NULL;
617 Mem_Free(shadowsides);
620 Mem_Free(shadowsideslist);
621 shadowsideslist = NULL;
622 r_shadow_buffer_numleafpvsbytes = 0;
623 if (r_shadow_buffer_visitingleafpvs)
624 Mem_Free(r_shadow_buffer_visitingleafpvs);
625 r_shadow_buffer_visitingleafpvs = NULL;
626 if (r_shadow_buffer_leafpvs)
627 Mem_Free(r_shadow_buffer_leafpvs);
628 r_shadow_buffer_leafpvs = NULL;
629 if (r_shadow_buffer_leaflist)
630 Mem_Free(r_shadow_buffer_leaflist);
631 r_shadow_buffer_leaflist = NULL;
632 r_shadow_buffer_numsurfacepvsbytes = 0;
633 if (r_shadow_buffer_surfacepvs)
634 Mem_Free(r_shadow_buffer_surfacepvs);
635 r_shadow_buffer_surfacepvs = NULL;
636 if (r_shadow_buffer_surfacelist)
637 Mem_Free(r_shadow_buffer_surfacelist);
638 r_shadow_buffer_surfacelist = NULL;
639 if (r_shadow_buffer_surfacesides)
640 Mem_Free(r_shadow_buffer_surfacesides);
641 r_shadow_buffer_surfacesides = NULL;
642 r_shadow_buffer_numshadowtrispvsbytes = 0;
643 if (r_shadow_buffer_shadowtrispvs)
644 Mem_Free(r_shadow_buffer_shadowtrispvs);
645 r_shadow_buffer_numlighttrispvsbytes = 0;
646 if (r_shadow_buffer_lighttrispvs)
647 Mem_Free(r_shadow_buffer_lighttrispvs);
650 void r_shadow_newmap(void)
652 if (r_shadow_bouncegridtexture) R_FreeTexture(r_shadow_bouncegridtexture);r_shadow_bouncegridtexture = NULL;
653 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
654 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
655 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
656 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
657 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
658 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
659 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
660 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
661 R_Shadow_EditLights_Reload_f();
664 void R_Shadow_Init(void)
666 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
667 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
668 Cvar_RegisterVariable(&r_shadow_usebihculling);
669 Cvar_RegisterVariable(&r_shadow_usenormalmap);
670 Cvar_RegisterVariable(&r_shadow_debuglight);
671 Cvar_RegisterVariable(&r_shadow_deferred);
672 Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
673 // Cvar_RegisterVariable(&r_shadow_deferred_fp);
674 Cvar_RegisterVariable(&r_shadow_gloss);
675 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
676 Cvar_RegisterVariable(&r_shadow_glossintensity);
677 Cvar_RegisterVariable(&r_shadow_glossexponent);
678 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
679 Cvar_RegisterVariable(&r_shadow_glossexact);
680 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
681 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
682 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
683 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
684 Cvar_RegisterVariable(&r_shadow_projectdistance);
685 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
686 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
687 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
688 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
689 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
690 Cvar_RegisterVariable(&r_shadow_realtime_world);
691 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
692 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
693 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
694 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
695 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
696 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
697 Cvar_RegisterVariable(&r_shadow_scissor);
698 Cvar_RegisterVariable(&r_shadow_shadowmapping);
699 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
700 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
701 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
702 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
703 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
704 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
705 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
706 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
707 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
708 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
709 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
710 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
711 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
712 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
713 Cvar_RegisterVariable(&r_shadow_polygonfactor);
714 Cvar_RegisterVariable(&r_shadow_polygonoffset);
715 Cvar_RegisterVariable(&r_shadow_texture3d);
716 Cvar_RegisterVariable(&r_shadow_bouncegrid);
717 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
718 Cvar_RegisterVariable(&r_shadow_bouncegrid_dlightparticlemultiplier);
719 Cvar_RegisterVariable(&r_shadow_bouncegrid_hitmodels);
720 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
721 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightradiusscale);
722 Cvar_RegisterVariable(&r_shadow_bouncegrid_maxbounce);
723 Cvar_RegisterVariable(&r_shadow_bouncegrid_nolerpsplat);
724 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
725 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
726 Cvar_RegisterVariable(&r_shadow_bouncegrid_photons);
727 Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingx);
728 Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingy);
729 Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingz);
730 Cvar_RegisterVariable(&r_shadow_bouncegrid_stablerandom);
731 Cvar_RegisterVariable(&r_shadow_bouncegrid_updateinterval);
732 Cvar_RegisterVariable(&r_shadow_bouncegrid_x);
733 Cvar_RegisterVariable(&r_shadow_bouncegrid_y);
734 Cvar_RegisterVariable(&r_shadow_bouncegrid_z);
735 Cvar_RegisterVariable(&r_coronas);
736 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
737 Cvar_RegisterVariable(&r_coronas_occlusionquery);
738 Cvar_RegisterVariable(&gl_flashblend);
739 Cvar_RegisterVariable(&gl_ext_separatestencil);
740 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
741 R_Shadow_EditLights_Init();
742 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
743 maxshadowtriangles = 0;
744 shadowelements = NULL;
745 maxshadowvertices = 0;
746 shadowvertex3f = NULL;
754 shadowmarklist = NULL;
759 shadowsideslist = NULL;
760 r_shadow_buffer_numleafpvsbytes = 0;
761 r_shadow_buffer_visitingleafpvs = NULL;
762 r_shadow_buffer_leafpvs = NULL;
763 r_shadow_buffer_leaflist = NULL;
764 r_shadow_buffer_numsurfacepvsbytes = 0;
765 r_shadow_buffer_surfacepvs = NULL;
766 r_shadow_buffer_surfacelist = NULL;
767 r_shadow_buffer_surfacesides = NULL;
768 r_shadow_buffer_shadowtrispvs = NULL;
769 r_shadow_buffer_lighttrispvs = NULL;
770 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
773 matrix4x4_t matrix_attenuationxyz =
776 {0.5, 0.0, 0.0, 0.5},
777 {0.0, 0.5, 0.0, 0.5},
778 {0.0, 0.0, 0.5, 0.5},
783 matrix4x4_t matrix_attenuationz =
786 {0.0, 0.0, 0.5, 0.5},
787 {0.0, 0.0, 0.0, 0.5},
788 {0.0, 0.0, 0.0, 0.5},
793 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
795 numvertices = ((numvertices + 255) & ~255) * vertscale;
796 numtriangles = ((numtriangles + 255) & ~255) * triscale;
797 // make sure shadowelements is big enough for this volume
798 if (maxshadowtriangles < numtriangles)
800 maxshadowtriangles = numtriangles;
802 Mem_Free(shadowelements);
803 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
805 // make sure shadowvertex3f is big enough for this volume
806 if (maxshadowvertices < numvertices)
808 maxshadowvertices = numvertices;
810 Mem_Free(shadowvertex3f);
811 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
815 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
817 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
818 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
819 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
820 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
821 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
823 if (r_shadow_buffer_visitingleafpvs)
824 Mem_Free(r_shadow_buffer_visitingleafpvs);
825 if (r_shadow_buffer_leafpvs)
826 Mem_Free(r_shadow_buffer_leafpvs);
827 if (r_shadow_buffer_leaflist)
828 Mem_Free(r_shadow_buffer_leaflist);
829 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
830 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
831 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
832 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
834 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
836 if (r_shadow_buffer_surfacepvs)
837 Mem_Free(r_shadow_buffer_surfacepvs);
838 if (r_shadow_buffer_surfacelist)
839 Mem_Free(r_shadow_buffer_surfacelist);
840 if (r_shadow_buffer_surfacesides)
841 Mem_Free(r_shadow_buffer_surfacesides);
842 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
843 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
844 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
845 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
847 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
849 if (r_shadow_buffer_shadowtrispvs)
850 Mem_Free(r_shadow_buffer_shadowtrispvs);
851 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
852 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
854 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
856 if (r_shadow_buffer_lighttrispvs)
857 Mem_Free(r_shadow_buffer_lighttrispvs);
858 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
859 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
863 void R_Shadow_PrepareShadowMark(int numtris)
865 // make sure shadowmark is big enough for this volume
866 if (maxshadowmark < numtris)
868 maxshadowmark = numtris;
870 Mem_Free(shadowmark);
872 Mem_Free(shadowmarklist);
873 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
874 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
878 // if shadowmarkcount wrapped we clear the array and adjust accordingly
879 if (shadowmarkcount == 0)
882 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
887 void R_Shadow_PrepareShadowSides(int numtris)
889 if (maxshadowsides < numtris)
891 maxshadowsides = numtris;
893 Mem_Free(shadowsides);
895 Mem_Free(shadowsideslist);
896 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
897 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
902 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)
905 int outtriangles = 0, outvertices = 0;
908 float ratio, direction[3], projectvector[3];
910 if (projectdirection)
911 VectorScale(projectdirection, projectdistance, projectvector);
913 VectorClear(projectvector);
915 // create the vertices
916 if (projectdirection)
918 for (i = 0;i < numshadowmarktris;i++)
920 element = inelement3i + shadowmarktris[i] * 3;
921 for (j = 0;j < 3;j++)
923 if (vertexupdate[element[j]] != vertexupdatenum)
925 vertexupdate[element[j]] = vertexupdatenum;
926 vertexremap[element[j]] = outvertices;
927 vertex = invertex3f + element[j] * 3;
928 // project one copy of the vertex according to projectvector
929 VectorCopy(vertex, outvertex3f);
930 VectorAdd(vertex, projectvector, (outvertex3f + 3));
939 for (i = 0;i < numshadowmarktris;i++)
941 element = inelement3i + shadowmarktris[i] * 3;
942 for (j = 0;j < 3;j++)
944 if (vertexupdate[element[j]] != vertexupdatenum)
946 vertexupdate[element[j]] = vertexupdatenum;
947 vertexremap[element[j]] = outvertices;
948 vertex = invertex3f + element[j] * 3;
949 // project one copy of the vertex to the sphere radius of the light
950 // (FIXME: would projecting it to the light box be better?)
951 VectorSubtract(vertex, projectorigin, direction);
952 ratio = projectdistance / VectorLength(direction);
953 VectorCopy(vertex, outvertex3f);
954 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
962 if (r_shadow_frontsidecasting.integer)
964 for (i = 0;i < numshadowmarktris;i++)
966 int remappedelement[3];
968 const int *neighbortriangle;
970 markindex = shadowmarktris[i] * 3;
971 element = inelement3i + markindex;
972 neighbortriangle = inneighbor3i + markindex;
973 // output the front and back triangles
974 outelement3i[0] = vertexremap[element[0]];
975 outelement3i[1] = vertexremap[element[1]];
976 outelement3i[2] = vertexremap[element[2]];
977 outelement3i[3] = vertexremap[element[2]] + 1;
978 outelement3i[4] = vertexremap[element[1]] + 1;
979 outelement3i[5] = vertexremap[element[0]] + 1;
983 // output the sides (facing outward from this triangle)
984 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
986 remappedelement[0] = vertexremap[element[0]];
987 remappedelement[1] = vertexremap[element[1]];
988 outelement3i[0] = remappedelement[1];
989 outelement3i[1] = remappedelement[0];
990 outelement3i[2] = remappedelement[0] + 1;
991 outelement3i[3] = remappedelement[1];
992 outelement3i[4] = remappedelement[0] + 1;
993 outelement3i[5] = remappedelement[1] + 1;
998 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1000 remappedelement[1] = vertexremap[element[1]];
1001 remappedelement[2] = vertexremap[element[2]];
1002 outelement3i[0] = remappedelement[2];
1003 outelement3i[1] = remappedelement[1];
1004 outelement3i[2] = remappedelement[1] + 1;
1005 outelement3i[3] = remappedelement[2];
1006 outelement3i[4] = remappedelement[1] + 1;
1007 outelement3i[5] = remappedelement[2] + 1;
1012 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1014 remappedelement[0] = vertexremap[element[0]];
1015 remappedelement[2] = vertexremap[element[2]];
1016 outelement3i[0] = remappedelement[0];
1017 outelement3i[1] = remappedelement[2];
1018 outelement3i[2] = remappedelement[2] + 1;
1019 outelement3i[3] = remappedelement[0];
1020 outelement3i[4] = remappedelement[2] + 1;
1021 outelement3i[5] = remappedelement[0] + 1;
1030 for (i = 0;i < numshadowmarktris;i++)
1032 int remappedelement[3];
1034 const int *neighbortriangle;
1036 markindex = shadowmarktris[i] * 3;
1037 element = inelement3i + markindex;
1038 neighbortriangle = inneighbor3i + markindex;
1039 // output the front and back triangles
1040 outelement3i[0] = vertexremap[element[2]];
1041 outelement3i[1] = vertexremap[element[1]];
1042 outelement3i[2] = vertexremap[element[0]];
1043 outelement3i[3] = vertexremap[element[0]] + 1;
1044 outelement3i[4] = vertexremap[element[1]] + 1;
1045 outelement3i[5] = vertexremap[element[2]] + 1;
1049 // output the sides (facing outward from this triangle)
1050 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1052 remappedelement[0] = vertexremap[element[0]];
1053 remappedelement[1] = vertexremap[element[1]];
1054 outelement3i[0] = remappedelement[0];
1055 outelement3i[1] = remappedelement[1];
1056 outelement3i[2] = remappedelement[1] + 1;
1057 outelement3i[3] = remappedelement[0];
1058 outelement3i[4] = remappedelement[1] + 1;
1059 outelement3i[5] = remappedelement[0] + 1;
1064 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1066 remappedelement[1] = vertexremap[element[1]];
1067 remappedelement[2] = vertexremap[element[2]];
1068 outelement3i[0] = remappedelement[1];
1069 outelement3i[1] = remappedelement[2];
1070 outelement3i[2] = remappedelement[2] + 1;
1071 outelement3i[3] = remappedelement[1];
1072 outelement3i[4] = remappedelement[2] + 1;
1073 outelement3i[5] = remappedelement[1] + 1;
1078 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1080 remappedelement[0] = vertexremap[element[0]];
1081 remappedelement[2] = vertexremap[element[2]];
1082 outelement3i[0] = remappedelement[2];
1083 outelement3i[1] = remappedelement[0];
1084 outelement3i[2] = remappedelement[0] + 1;
1085 outelement3i[3] = remappedelement[2];
1086 outelement3i[4] = remappedelement[0] + 1;
1087 outelement3i[5] = remappedelement[2] + 1;
1095 *outnumvertices = outvertices;
1096 return outtriangles;
1099 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)
1102 int outtriangles = 0, outvertices = 0;
1104 const float *vertex;
1105 float ratio, direction[3], projectvector[3];
1108 if (projectdirection)
1109 VectorScale(projectdirection, projectdistance, projectvector);
1111 VectorClear(projectvector);
1113 for (i = 0;i < numshadowmarktris;i++)
1115 int remappedelement[3];
1117 const int *neighbortriangle;
1119 markindex = shadowmarktris[i] * 3;
1120 neighbortriangle = inneighbor3i + markindex;
1121 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1122 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1123 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1124 if (side[0] + side[1] + side[2] == 0)
1128 element = inelement3i + markindex;
1130 // create the vertices
1131 for (j = 0;j < 3;j++)
1133 if (side[j] + side[j+1] == 0)
1136 if (vertexupdate[k] != vertexupdatenum)
1138 vertexupdate[k] = vertexupdatenum;
1139 vertexremap[k] = outvertices;
1140 vertex = invertex3f + k * 3;
1141 VectorCopy(vertex, outvertex3f);
1142 if (projectdirection)
1144 // project one copy of the vertex according to projectvector
1145 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1149 // project one copy of the vertex to the sphere radius of the light
1150 // (FIXME: would projecting it to the light box be better?)
1151 VectorSubtract(vertex, projectorigin, direction);
1152 ratio = projectdistance / VectorLength(direction);
1153 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1160 // output the sides (facing outward from this triangle)
1163 remappedelement[0] = vertexremap[element[0]];
1164 remappedelement[1] = vertexremap[element[1]];
1165 outelement3i[0] = remappedelement[1];
1166 outelement3i[1] = remappedelement[0];
1167 outelement3i[2] = remappedelement[0] + 1;
1168 outelement3i[3] = remappedelement[1];
1169 outelement3i[4] = remappedelement[0] + 1;
1170 outelement3i[5] = remappedelement[1] + 1;
1177 remappedelement[1] = vertexremap[element[1]];
1178 remappedelement[2] = vertexremap[element[2]];
1179 outelement3i[0] = remappedelement[2];
1180 outelement3i[1] = remappedelement[1];
1181 outelement3i[2] = remappedelement[1] + 1;
1182 outelement3i[3] = remappedelement[2];
1183 outelement3i[4] = remappedelement[1] + 1;
1184 outelement3i[5] = remappedelement[2] + 1;
1191 remappedelement[0] = vertexremap[element[0]];
1192 remappedelement[2] = vertexremap[element[2]];
1193 outelement3i[0] = remappedelement[0];
1194 outelement3i[1] = remappedelement[2];
1195 outelement3i[2] = remappedelement[2] + 1;
1196 outelement3i[3] = remappedelement[0];
1197 outelement3i[4] = remappedelement[2] + 1;
1198 outelement3i[5] = remappedelement[0] + 1;
1205 *outnumvertices = outvertices;
1206 return outtriangles;
1209 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)
1215 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1217 tend = firsttriangle + numtris;
1218 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1220 // surface box entirely inside light box, no box cull
1221 if (projectdirection)
1223 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1225 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1226 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1227 shadowmarklist[numshadowmark++] = t;
1232 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1233 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1234 shadowmarklist[numshadowmark++] = t;
1239 // surface box not entirely inside light box, cull each triangle
1240 if (projectdirection)
1242 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1244 v[0] = invertex3f + e[0] * 3;
1245 v[1] = invertex3f + e[1] * 3;
1246 v[2] = invertex3f + e[2] * 3;
1247 TriangleNormal(v[0], v[1], v[2], normal);
1248 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1249 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1250 shadowmarklist[numshadowmark++] = t;
1255 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1257 v[0] = invertex3f + e[0] * 3;
1258 v[1] = invertex3f + e[1] * 3;
1259 v[2] = invertex3f + e[2] * 3;
1260 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1261 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1262 shadowmarklist[numshadowmark++] = t;
1268 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1273 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1275 // check if the shadow volume intersects the near plane
1277 // a ray between the eye and light origin may intersect the caster,
1278 // indicating that the shadow may touch the eye location, however we must
1279 // test the near plane (a polygon), not merely the eye location, so it is
1280 // easiest to enlarge the caster bounding shape slightly for this.
1286 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)
1288 int i, tris, outverts;
1289 if (projectdistance < 0.1)
1291 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1294 if (!numverts || !nummarktris)
1296 // make sure shadowelements is big enough for this volume
1297 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1298 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1300 if (maxvertexupdate < numverts)
1302 maxvertexupdate = numverts;
1304 Mem_Free(vertexupdate);
1306 Mem_Free(vertexremap);
1307 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1308 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1309 vertexupdatenum = 0;
1312 if (vertexupdatenum == 0)
1314 vertexupdatenum = 1;
1315 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1316 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1319 for (i = 0;i < nummarktris;i++)
1320 shadowmark[marktris[i]] = shadowmarkcount;
1322 if (r_shadow_compilingrtlight)
1324 // if we're compiling an rtlight, capture the mesh
1325 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1326 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1327 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1328 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1330 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1332 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1333 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1334 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1338 // decide which type of shadow to generate and set stencil mode
1339 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1340 // generate the sides or a solid volume, depending on type
1341 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1342 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1344 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1345 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1346 r_refdef.stats.lights_shadowtriangles += tris;
1347 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1349 // increment stencil if frontface is infront of depthbuffer
1350 GL_CullFace(r_refdef.view.cullface_front);
1351 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1352 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1353 // decrement stencil if backface is infront of depthbuffer
1354 GL_CullFace(r_refdef.view.cullface_back);
1355 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1357 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1359 // decrement stencil if backface is behind depthbuffer
1360 GL_CullFace(r_refdef.view.cullface_front);
1361 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1362 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1363 // increment stencil if frontface is behind depthbuffer
1364 GL_CullFace(r_refdef.view.cullface_back);
1365 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1367 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1368 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1372 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1374 // p1, p2, p3 are in the cubemap's local coordinate system
1375 // bias = border/(size - border)
1378 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1379 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1380 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1381 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1383 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1384 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1385 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1386 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1388 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1389 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1390 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1392 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1393 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1394 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1395 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1397 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1398 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1399 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1400 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1402 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1403 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1404 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1406 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1407 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1408 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1409 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1411 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1412 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1413 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1414 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1416 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1417 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1418 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1423 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1425 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1426 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1429 VectorSubtract(maxs, mins, radius);
1430 VectorScale(radius, 0.5f, radius);
1431 VectorAdd(mins, radius, center);
1432 Matrix4x4_Transform(worldtolight, center, lightcenter);
1433 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1434 VectorSubtract(lightcenter, lightradius, pmin);
1435 VectorAdd(lightcenter, lightradius, pmax);
1437 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1438 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1439 if(ap1 > bias*an1 && ap2 > bias*an2)
1441 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1442 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1443 if(an1 > bias*ap1 && an2 > bias*ap2)
1445 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1446 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1448 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1449 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1450 if(ap1 > bias*an1 && ap2 > bias*an2)
1452 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1453 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1454 if(an1 > bias*ap1 && an2 > bias*ap2)
1456 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1457 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1459 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1460 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1461 if(ap1 > bias*an1 && ap2 > bias*an2)
1463 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1464 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1465 if(an1 > bias*ap1 && an2 > bias*ap2)
1467 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1468 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1473 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1475 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1477 // p is in the cubemap's local coordinate system
1478 // bias = border/(size - border)
1479 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1480 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1481 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1483 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1484 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1485 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1486 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1487 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1488 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1492 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1496 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1497 float scale = (size - 2*border)/size, len;
1498 float bias = border / (float)(size - border), dp, dn, ap, an;
1499 // check if cone enclosing side would cross frustum plane
1500 scale = 2 / (scale*scale + 2);
1501 for (i = 0;i < 5;i++)
1503 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1505 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1506 len = scale*VectorLength2(n);
1507 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1508 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1509 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1511 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1513 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1514 len = scale*VectorLength(n);
1515 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1516 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1517 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1519 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1520 // check if frustum corners/origin cross plane sides
1522 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1523 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1524 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1525 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1526 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1527 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1528 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1529 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1530 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1531 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1532 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1533 for (i = 0;i < 4;i++)
1535 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1536 VectorSubtract(n, p, n);
1537 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1538 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1539 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1540 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1541 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1542 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1543 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1544 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1545 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1548 // finite version, assumes corners are a finite distance from origin dependent on far plane
1549 for (i = 0;i < 5;i++)
1551 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1552 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1553 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1554 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1555 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1556 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1557 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1558 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1559 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1560 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1563 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1566 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)
1574 int mask, surfacemask = 0;
1575 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1577 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1578 tend = firsttriangle + numtris;
1579 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1581 // surface box entirely inside light box, no box cull
1582 if (projectdirection)
1584 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1586 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1587 TriangleNormal(v[0], v[1], v[2], normal);
1588 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1590 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1591 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1592 surfacemask |= mask;
1595 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;
1596 shadowsides[numshadowsides] = mask;
1597 shadowsideslist[numshadowsides++] = t;
1604 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1606 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1607 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1609 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1610 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1611 surfacemask |= mask;
1614 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;
1615 shadowsides[numshadowsides] = mask;
1616 shadowsideslist[numshadowsides++] = t;
1624 // surface box not entirely inside light box, cull each triangle
1625 if (projectdirection)
1627 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1629 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1630 TriangleNormal(v[0], v[1], v[2], normal);
1631 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1632 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1634 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1635 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1636 surfacemask |= mask;
1639 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;
1640 shadowsides[numshadowsides] = mask;
1641 shadowsideslist[numshadowsides++] = t;
1648 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1650 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1651 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1652 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1654 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1655 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1656 surfacemask |= mask;
1659 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;
1660 shadowsides[numshadowsides] = mask;
1661 shadowsideslist[numshadowsides++] = t;
1670 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)
1672 int i, j, outtriangles = 0;
1673 int *outelement3i[6];
1674 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1676 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1677 // make sure shadowelements is big enough for this mesh
1678 if (maxshadowtriangles < outtriangles)
1679 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1681 // compute the offset and size of the separate index lists for each cubemap side
1683 for (i = 0;i < 6;i++)
1685 outelement3i[i] = shadowelements + outtriangles * 3;
1686 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1687 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1688 outtriangles += sidetotals[i];
1691 // gather up the (sparse) triangles into separate index lists for each cubemap side
1692 for (i = 0;i < numsidetris;i++)
1694 const int *element = elements + sidetris[i] * 3;
1695 for (j = 0;j < 6;j++)
1697 if (sides[i] & (1 << j))
1699 outelement3i[j][0] = element[0];
1700 outelement3i[j][1] = element[1];
1701 outelement3i[j][2] = element[2];
1702 outelement3i[j] += 3;
1707 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1710 static void R_Shadow_MakeTextures_MakeCorona(void)
1714 unsigned char pixels[32][32][4];
1715 for (y = 0;y < 32;y++)
1717 dy = (y - 15.5f) * (1.0f / 16.0f);
1718 for (x = 0;x < 32;x++)
1720 dx = (x - 15.5f) * (1.0f / 16.0f);
1721 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1722 a = bound(0, a, 255);
1723 pixels[y][x][0] = a;
1724 pixels[y][x][1] = a;
1725 pixels[y][x][2] = a;
1726 pixels[y][x][3] = 255;
1729 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1732 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1734 float dist = sqrt(x*x+y*y+z*z);
1735 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1736 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1737 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1740 static void R_Shadow_MakeTextures(void)
1743 float intensity, dist;
1745 R_Shadow_FreeShadowMaps();
1746 R_FreeTexturePool(&r_shadow_texturepool);
1747 r_shadow_texturepool = R_AllocTexturePool();
1748 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1749 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1750 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1751 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1752 for (x = 0;x <= ATTENTABLESIZE;x++)
1754 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1755 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1756 r_shadow_attentable[x] = bound(0, intensity, 1);
1758 // 1D gradient texture
1759 for (x = 0;x < ATTEN1DSIZE;x++)
1760 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1761 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1762 // 2D circle texture
1763 for (y = 0;y < ATTEN2DSIZE;y++)
1764 for (x = 0;x < ATTEN2DSIZE;x++)
1765 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);
1766 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1767 // 3D sphere texture
1768 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1770 for (z = 0;z < ATTEN3DSIZE;z++)
1771 for (y = 0;y < ATTEN3DSIZE;y++)
1772 for (x = 0;x < ATTEN3DSIZE;x++)
1773 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));
1774 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);
1777 r_shadow_attenuation3dtexture = NULL;
1780 R_Shadow_MakeTextures_MakeCorona();
1782 // Editor light sprites
1783 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1800 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1801 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1818 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1819 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1836 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1837 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1854 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1855 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1872 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1873 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1890 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1893 void R_Shadow_ValidateCvars(void)
1895 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1896 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1897 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1898 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1899 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1900 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1903 void R_Shadow_RenderMode_Begin(void)
1909 R_Shadow_ValidateCvars();
1911 if (!r_shadow_attenuation2dtexture
1912 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1913 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1914 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1915 R_Shadow_MakeTextures();
1918 R_Mesh_ResetTextureState();
1919 GL_BlendFunc(GL_ONE, GL_ZERO);
1920 GL_DepthRange(0, 1);
1921 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1923 GL_DepthMask(false);
1924 GL_Color(0, 0, 0, 1);
1925 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1927 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1929 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1931 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1932 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1934 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1936 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1937 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1941 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1942 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1945 switch(vid.renderpath)
1947 case RENDERPATH_GL20:
1948 case RENDERPATH_D3D9:
1949 case RENDERPATH_D3D10:
1950 case RENDERPATH_D3D11:
1951 case RENDERPATH_SOFT:
1952 case RENDERPATH_GLES2:
1953 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1955 case RENDERPATH_GL13:
1956 case RENDERPATH_GL11:
1957 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1958 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1959 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1960 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1961 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1962 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1964 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1970 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1971 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1972 r_shadow_drawbuffer = drawbuffer;
1973 r_shadow_readbuffer = readbuffer;
1975 r_shadow_cullface_front = r_refdef.view.cullface_front;
1976 r_shadow_cullface_back = r_refdef.view.cullface_back;
1979 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1981 rsurface.rtlight = rtlight;
1984 void R_Shadow_RenderMode_Reset(void)
1986 R_Mesh_ResetRenderTargets();
1987 R_SetViewport(&r_refdef.view.viewport);
1988 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1989 R_Mesh_ResetTextureState();
1990 GL_DepthRange(0, 1);
1992 GL_DepthMask(false);
1993 GL_DepthFunc(GL_LEQUAL);
1994 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1995 r_refdef.view.cullface_front = r_shadow_cullface_front;
1996 r_refdef.view.cullface_back = r_shadow_cullface_back;
1997 GL_CullFace(r_refdef.view.cullface_back);
1998 GL_Color(1, 1, 1, 1);
1999 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2000 GL_BlendFunc(GL_ONE, GL_ZERO);
2001 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
2002 r_shadow_usingshadowmap2d = false;
2003 r_shadow_usingshadowmaportho = false;
2004 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2007 void R_Shadow_ClearStencil(void)
2009 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2010 r_refdef.stats.lights_clears++;
2013 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2015 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2016 if (r_shadow_rendermode == mode)
2018 R_Shadow_RenderMode_Reset();
2019 GL_DepthFunc(GL_LESS);
2020 GL_ColorMask(0, 0, 0, 0);
2021 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2022 GL_CullFace(GL_NONE);
2023 R_SetupShader_DepthOrShadow();
2024 r_shadow_rendermode = mode;
2029 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2030 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2031 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2033 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2034 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2035 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2040 static void R_Shadow_MakeVSDCT(void)
2042 // maps to a 2x3 texture rectangle with normalized coordinates
2047 // stores abs(dir.xy), offset.xy/2.5
2048 unsigned char data[4*6] =
2050 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2051 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2052 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2053 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2054 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2055 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2057 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2060 static void R_Shadow_MakeShadowMap(int side, int size)
2062 switch (r_shadow_shadowmode)
2064 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2065 if (r_shadow_shadowmap2dtexture) return;
2066 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2067 r_shadow_shadowmap2dcolortexture = NULL;
2068 switch(vid.renderpath)
2071 case RENDERPATH_D3D9:
2072 r_shadow_shadowmap2dcolortexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), NULL, TEXTYPE_BGRA, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2073 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2077 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, NULL, NULL, NULL, NULL);
2085 // render depth into the fbo, do not render color at all
2086 // validate the fbo now
2090 qglDrawBuffer(GL_NONE);CHECKGLERROR
2091 qglReadBuffer(GL_NONE);CHECKGLERROR
2092 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2093 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2095 Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2096 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2097 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2102 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2104 float nearclip, farclip, bias;
2105 r_viewport_t viewport;
2108 float clearcolor[4];
2109 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2111 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2112 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2113 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2114 r_shadow_shadowmapside = side;
2115 r_shadow_shadowmapsize = size;
2117 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2118 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2119 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2120 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2122 // complex unrolled cube approach (more flexible)
2123 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2124 R_Shadow_MakeVSDCT();
2125 if (!r_shadow_shadowmap2dtexture)
2126 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2127 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2128 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2129 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2130 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2132 R_Mesh_ResetTextureState();
2133 R_Mesh_ResetRenderTargets();
2134 R_Shadow_RenderMode_Reset();
2137 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2138 R_SetupShader_DepthOrShadow();
2141 R_SetupShader_ShowDepth();
2142 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2147 R_SetViewport(&viewport);
2148 flipped = (side & 1) ^ (side >> 2);
2149 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2150 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2151 switch(vid.renderpath)
2153 case RENDERPATH_GL11:
2154 case RENDERPATH_GL13:
2155 case RENDERPATH_GL20:
2156 case RENDERPATH_SOFT:
2157 case RENDERPATH_GLES2:
2158 GL_CullFace(r_refdef.view.cullface_back);
2159 // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
2160 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2162 // get tightest scissor rectangle that encloses all viewports in the clear mask
2163 int x1 = clear & 0x15 ? 0 : size;
2164 int x2 = clear & 0x2A ? 2 * size : size;
2165 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2166 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2167 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2168 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2170 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2172 case RENDERPATH_D3D9:
2173 case RENDERPATH_D3D10:
2174 case RENDERPATH_D3D11:
2175 Vector4Set(clearcolor, 1,1,1,1);
2176 // completely different meaning than in OpenGL path
2177 r_shadow_shadowmap_parameters[1] = 0;
2178 r_shadow_shadowmap_parameters[3] = -bias;
2179 // we invert the cull mode because we flip the projection matrix
2180 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2181 GL_CullFace(r_refdef.view.cullface_front);
2182 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2183 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2184 if (r_shadow_shadowmapsampler)
2186 GL_ColorMask(0,0,0,0);
2188 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2192 GL_ColorMask(1,1,1,1);
2194 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2200 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2202 R_Mesh_ResetTextureState();
2203 R_Mesh_ResetRenderTargets();
2206 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2207 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2208 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2209 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2211 R_Shadow_RenderMode_Reset();
2212 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2214 GL_DepthFunc(GL_EQUAL);
2215 // do global setup needed for the chosen lighting mode
2216 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2217 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2218 r_shadow_usingshadowmap2d = shadowmapping;
2219 r_shadow_rendermode = r_shadow_lightingrendermode;
2220 // only draw light where this geometry was already rendered AND the
2221 // stencil is 128 (values other than this mean shadow)
2223 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2225 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2228 static const unsigned short bboxelements[36] =
2238 static const float bboxpoints[8][3] =
2250 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2253 float vertex3f[8*3];
2254 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2255 // do global setup needed for the chosen lighting mode
2256 R_Shadow_RenderMode_Reset();
2257 r_shadow_rendermode = r_shadow_lightingrendermode;
2258 R_EntityMatrix(&identitymatrix);
2259 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2260 // only draw light where this geometry was already rendered AND the
2261 // stencil is 128 (values other than this mean shadow)
2262 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2263 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2265 r_shadow_usingshadowmap2d = shadowmapping;
2267 // render the lighting
2268 R_SetupShader_DeferredLight(rsurface.rtlight);
2269 for (i = 0;i < 8;i++)
2270 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2271 GL_ColorMask(1,1,1,1);
2272 GL_DepthMask(false);
2273 GL_DepthRange(0, 1);
2274 GL_PolygonOffset(0, 0);
2276 GL_DepthFunc(GL_GREATER);
2277 GL_CullFace(r_refdef.view.cullface_back);
2278 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL);
2279 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2282 static void R_Shadow_UpdateBounceGridTexture(void)
2284 #define MAXBOUNCEGRIDPARTICLESPERLIGHT 1048576
2286 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2289 int hitsupercontentsmask;
2298 //trace_t cliptrace2;
2299 //trace_t cliptrace3;
2300 unsigned char *pixel;
2301 unsigned char *pixels;
2302 unsigned short *highpixel;
2303 unsigned short *highpixels;
2304 unsigned int lightindex;
2306 unsigned int range1;
2307 unsigned int range2;
2308 unsigned int seed = (unsigned int)(realtime * 1000.0f);
2310 vec3_t baseshotcolor;
2323 vec_t lightintensity;
2324 vec_t photonscaling;
2325 vec_t photonresidual;
2332 qboolean isstatic = r_shadow_bouncegrid_updateinterval.value > 1.0f;
2334 if (!r_shadow_bouncegrid.integer || !vid.support.ext_texture_3d)
2336 if (r_shadow_bouncegridtexture)
2338 R_FreeTexture(r_shadow_bouncegridtexture);
2339 r_shadow_bouncegridtexture = NULL;
2341 if (r_shadow_bouncegridpixels)
2342 Mem_Free(r_shadow_bouncegridpixels);
2343 r_shadow_bouncegridpixels = NULL;
2344 if (r_shadow_bouncegridhighpixels)
2345 Mem_Free(r_shadow_bouncegridhighpixels);
2346 r_shadow_bouncegridhighpixels = NULL;
2347 r_shadow_bouncegridnumpixels = 0;
2350 if (r_refdef.scene.worldmodel && isstatic)
2352 VectorSet(spacing, bound(1, r_shadow_bouncegrid_spacingx.value, 512), bound(1, r_shadow_bouncegrid_spacingy.value, 512), bound(1, r_shadow_bouncegrid_spacingz.value, 512));
2353 VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
2354 VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
2355 VectorSubtract(maxs, mins, size);
2356 resolution[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2357 resolution[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2358 resolution[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2359 resolution[0] = min(resolution[0], bound(4, r_shadow_bouncegrid_x.integer, (int)vid.maxtexturesize_3d));
2360 resolution[1] = min(resolution[1], bound(4, r_shadow_bouncegrid_y.integer, (int)vid.maxtexturesize_3d));
2361 resolution[2] = min(resolution[2], bound(4, r_shadow_bouncegrid_z.integer, (int)vid.maxtexturesize_3d));
2362 spacing[0] = size[0] / resolution[0];
2363 spacing[1] = size[1] / resolution[1];
2364 spacing[2] = size[2] / resolution[2];
2365 ispacing[0] = 1.0f / spacing[0];
2366 ispacing[1] = 1.0f / spacing[1];
2367 ispacing[2] = 1.0f / spacing[2];
2371 VectorSet(resolution, bound(4, r_shadow_bouncegrid_x.integer, (int)vid.maxtexturesize_3d), bound(4, r_shadow_bouncegrid_y.integer, (int)vid.maxtexturesize_3d), bound(4, r_shadow_bouncegrid_z.integer, (int)vid.maxtexturesize_3d));
2372 VectorSet(spacing, bound(1, r_shadow_bouncegrid_spacingx.value, 512), bound(1, r_shadow_bouncegrid_spacingy.value, 512), bound(1, r_shadow_bouncegrid_spacingz.value, 512));
2373 VectorMultiply(resolution, spacing, size);
2374 ispacing[0] = 1.0f / spacing[0];
2375 ispacing[1] = 1.0f / spacing[1];
2376 ispacing[2] = 1.0f / spacing[2];
2377 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2378 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2379 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2380 VectorAdd(mins, size, maxs);
2382 r_shadow_bouncegridintensity = r_shadow_bouncegrid_intensity.value;
2383 if (r_shadow_bouncegridtexture && realtime < r_shadow_bouncegridtime + r_shadow_bouncegrid_updateinterval.value && resolution[0] == r_shadow_bouncegridresolution[0] && resolution[1] == r_shadow_bouncegridresolution[1] && resolution[2] == r_shadow_bouncegridresolution[2])
2385 // we're going to update the bouncegrid, update the matrix...
2386 memset(m, 0, sizeof(m));
2387 m[0] = 1.0f / size[0];
2388 m[3] = -mins[0] * m[0];
2389 m[5] = 1.0f / size[1];
2390 m[7] = -mins[1] * m[5];
2391 m[10] = 1.0f / size[2];
2392 m[11] = -mins[2] * m[10];
2394 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegridmatrix, m);
2395 numpixels = resolution[0]*resolution[1]*resolution[2];
2396 // reallocate pixels for this update if needed...
2397 if (r_shadow_bouncegridnumpixels != numpixels || !r_shadow_bouncegridpixels || !r_shadow_bouncegridhighpixels)
2399 r_shadow_bouncegridpixels = (unsigned char *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridpixels, numpixels * sizeof(unsigned char[4]));
2400 r_shadow_bouncegridhighpixels = (unsigned short *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridhighpixels, numpixels * sizeof(unsigned short[4]));
2402 r_shadow_bouncegridnumpixels = numpixels;
2403 pixels = r_shadow_bouncegridpixels;
2404 highpixels = r_shadow_bouncegridhighpixels;
2405 memset(pixels, 0, numpixels * sizeof(unsigned char[4]));
2406 memset(highpixels, 0, numpixels * sizeof(unsigned short[3]));
2407 // figure out what we want to interact with
2408 if (r_shadow_bouncegrid_hitmodels.integer)
2409 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK;
2411 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
2412 maxbounce = bound(1, r_shadow_bouncegrid_maxbounce.integer, 16);
2413 // iterate world rtlights
2414 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2415 range1 = isstatic ? 0 : r_refdef.scene.numlights;
2416 range2 = range + range1;
2418 for (lightindex = 0;lightindex < range2;lightindex++)
2422 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2423 if (!light || !(light->flags & flag))
2425 rtlight = &light->rtlight;
2426 // when static, we skip styled lights because they tend to change...
2427 if (rtlight->style > 0)
2429 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) * (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1), lightcolor);
2433 if (lightindex < range)
2435 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2436 rtlight = &light->rtlight;
2439 rtlight = r_refdef.scene.lights[lightindex - range];
2440 // draw only visible lights (major speedup)
2443 VectorScale(rtlight->currentcolor, rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale, lightcolor);
2445 if (!VectorLength2(lightcolor))
2447 // shoot particles from this light
2448 // use a calculation for the number of particles that will not
2449 // vary with lightstyle, otherwise we get randomized particle
2450 // distribution, the seeded random is only consistent for a
2451 // consistent number of particles on this light...
2452 radius = rtlight->radius * bound(0.0001f, r_shadow_bouncegrid_lightradiusscale.value, 1024.0f);
2453 s = rtlight->radius;
2454 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2455 if (lightindex >= range)
2456 lightintensity *= r_shadow_bouncegrid_dlightparticlemultiplier.value;
2457 photoncount += max(0.0f, lightintensity * s * s);
2459 photonscaling = bound(1, r_shadow_bouncegrid_photons.value, 1048576) / max(1, photoncount);
2460 photonresidual = 0.0f;
2461 for (lightindex = 0;lightindex < range2;lightindex++)
2465 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2466 if (!light || !(light->flags & flag))
2468 rtlight = &light->rtlight;
2469 // when static, we skip styled lights because they tend to change...
2470 if (rtlight->style > 0)
2472 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) * (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1), lightcolor);
2476 if (lightindex < range)
2478 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2479 rtlight = &light->rtlight;
2482 rtlight = r_refdef.scene.lights[lightindex - range];
2483 // draw only visible lights (major speedup)
2486 VectorScale(rtlight->currentcolor, rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale, lightcolor);
2488 if (!VectorLength2(lightcolor))
2490 // shoot particles from this light
2491 // use a calculation for the number of particles that will not
2492 // vary with lightstyle, otherwise we get randomized particle
2493 // distribution, the seeded random is only consistent for a
2494 // consistent number of particles on this light...
2495 radius = rtlight->radius * bound(0.0001f, r_shadow_bouncegrid_lightradiusscale.value, 1024.0f);
2496 s = rtlight->radius;
2497 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2498 if (lightindex >= range)
2499 lightintensity *= r_shadow_bouncegrid_dlightparticlemultiplier.value;
2500 photonresidual += lightintensity * s * s * photonscaling;
2501 shootparticles = (int)bound(0, photonresidual, MAXBOUNCEGRIDPARTICLESPERLIGHT);
2502 if (!shootparticles)
2504 photonresidual -= shootparticles;
2505 s = 65535.0f * r_shadow_bouncegrid_particleintensity.value / shootparticles;
2506 VectorScale(lightcolor, s, baseshotcolor);
2507 if (VectorLength2(baseshotcolor) < 3.0f)
2509 r_refdef.stats.bouncegrid_lights++;
2510 r_refdef.stats.bouncegrid_particles += shootparticles;
2511 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2513 if (r_shadow_bouncegrid_stablerandom.integer > 0)
2514 seed = lightindex * 11937 + shotparticles;
2515 VectorCopy(baseshotcolor, shotcolor);
2516 VectorCopy(rtlight->shadoworigin, clipstart);
2517 if (r_shadow_bouncegrid_stablerandom.integer < 0)
2518 VectorRandom(clipend);
2520 VectorCheeseRandom(clipend);
2521 VectorMA(clipstart, radius, clipend, clipend);
2522 for (bouncecount = 0;;bouncecount++)
2524 r_refdef.stats.bouncegrid_traces++;
2525 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2526 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2527 cliptrace = CL_TraceLine(clipstart, clipend, r_shadow_bouncegrid_hitmodels.integer ? MOVE_HITMODEL : MOVE_NOMONSTERS, NULL, hitsupercontentsmask, true, false, NULL, true, true);
2528 //Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask);
2529 if (cliptrace.fraction >= 1.0f)
2531 r_refdef.stats.bouncegrid_hits++;
2532 if (bouncecount > 0)
2534 r_refdef.stats.bouncegrid_splats++;
2535 // figure out which texture pixel this is in
2536 texlerp[1][0] = (int)(((cliptrace.endpos[0] - mins[0]) * ispacing[0]) * 256.0f);
2537 texlerp[1][1] = (int)(((cliptrace.endpos[1] - mins[1]) * ispacing[1]) * 256.0f);
2538 texlerp[1][2] = (int)(((cliptrace.endpos[2] - mins[2]) * ispacing[2]) * 256.0f);
2539 tex[0] = texlerp[1][0] >> 8;
2540 tex[1] = texlerp[1][1] >> 8;
2541 tex[2] = texlerp[1][2] >> 8;
2542 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)
2544 // it is within bounds...
2545 splatcolor[0] = (int)shotcolor[2];
2546 splatcolor[1] = (int)shotcolor[1];
2547 splatcolor[2] = (int)shotcolor[0];
2548 // calculate the lerp factors
2549 if (r_shadow_bouncegrid_nolerpsplat.integer)
2551 pixelindex[0] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0] );
2552 pixel = pixels + 4 * pixelindex[0];
2553 highpixel = highpixels + 3 * pixelindex[0];
2554 // add to the high precision pixel color
2555 c[0] = highpixel[0] + splatcolor[0];
2556 c[1] = highpixel[1] + splatcolor[1];
2557 c[2] = highpixel[2] + splatcolor[2];
2558 highpixel[0] = (unsigned short)min(c[0], 65535);
2559 highpixel[1] = (unsigned short)min(c[1], 65535);
2560 highpixel[2] = (unsigned short)min(c[2], 65535);
2561 // update the low precision pixel color
2562 pixel[0] = highpixel[0] >> 8;
2563 pixel[1] = highpixel[1] >> 8;
2564 pixel[2] = highpixel[2] >> 8;
2569 texlerp[1][0] &= 0xFF;
2570 texlerp[1][1] &= 0xFF;
2571 texlerp[1][2] &= 0xFF;
2572 texlerp[0][0] = 256 - texlerp[1][0];
2573 texlerp[0][1] = 256 - texlerp[1][1];
2574 texlerp[0][2] = 256 - texlerp[1][2];
2575 // calculate individual pixel indexes and weights
2576 pixelindex[0] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[0] = (texlerp[0][0]*texlerp[0][1]*texlerp[0][2]) >> 16;
2577 pixelindex[1] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0]+1);pixelweight[1] = (texlerp[1][0]*texlerp[0][1]*texlerp[0][2]) >> 16;
2578 pixelindex[2] = (((tex[2] )*resolution[1]+tex[1]+1)*resolution[0]+tex[0] );pixelweight[2] = (texlerp[0][0]*texlerp[1][1]*texlerp[0][2]) >> 16;
2579 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]) >> 16;
2580 pixelindex[4] = (((tex[2]+1)*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[4] = (texlerp[0][0]*texlerp[0][1]*texlerp[1][2]) >> 16;
2581 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]) >> 16;
2582 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]) >> 16;
2583 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]) >> 16;
2584 // update the 8 pixels...
2585 for (corner = 0;corner < 8;corner++)
2587 pixel = pixels + 4 * pixelindex[corner];
2588 highpixel = highpixels + 3 * pixelindex[corner];
2589 // add to the high precision pixel color
2590 c[0] = highpixel[0] + ((splatcolor[0]*pixelweight[corner])>>8);
2591 c[1] = highpixel[1] + ((splatcolor[1]*pixelweight[corner])>>8);
2592 c[2] = highpixel[2] + ((splatcolor[2]*pixelweight[corner])>>8);
2593 highpixel[0] = (unsigned short)min(c[0], 65535);
2594 highpixel[1] = (unsigned short)min(c[1], 65535);
2595 highpixel[2] = (unsigned short)min(c[2], 65535);
2596 // update the low precision pixel color
2597 pixel[0] = highpixel[0] >> 8;
2598 pixel[1] = highpixel[1] >> 8;
2599 pixel[2] = highpixel[2] >> 8;
2605 if (bouncecount >= maxbounce)
2607 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2608 // also clamp the resulting color to never add energy, even if the user requests extreme values
2609 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2610 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
2612 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
2613 VectorScale(surfcolor, r_shadow_bouncegrid_particlebounceintensity.value, surfcolor);
2614 surfcolor[0] = min(surfcolor[0], 1.0f);
2615 surfcolor[1] = min(surfcolor[1], 1.0f);
2616 surfcolor[2] = min(surfcolor[2], 1.0f);
2617 VectorMultiply(shotcolor, surfcolor, shotcolor);
2618 if (VectorLength2(shotcolor) < 3.0f)
2620 r_refdef.stats.bouncegrid_bounces++;
2621 if (r_shadow_bouncegrid_bounceanglediffuse.integer)
2623 // random direction, primarily along plane normal
2624 s = VectorDistance(cliptrace.endpos, clipend);
2625 if (r_shadow_bouncegrid_stablerandom.integer < 0)
2626 VectorRandom(clipend);
2628 VectorCheeseRandom(clipend);
2629 VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
2630 VectorNormalize(clipend);
2631 VectorScale(clipend, s, clipend);
2635 // reflect the remaining portion of the line across plane normal
2636 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2637 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2639 // calculate the new line start and end
2640 VectorCopy(cliptrace.endpos, clipstart);
2641 VectorAdd(clipstart, clipend, clipend);
2645 if (r_shadow_bouncegridtexture && r_shadow_bouncegridresolution[0] == resolution[0] && r_shadow_bouncegridresolution[1] == resolution[1] && r_shadow_bouncegridresolution[2] == resolution[2])
2646 R_UpdateTexture(r_shadow_bouncegridtexture, pixels, 0, 0, 0, resolution[0], resolution[1], resolution[2]);
2649 VectorCopy(resolution, r_shadow_bouncegridresolution);
2650 if (r_shadow_bouncegridtexture)
2651 R_FreeTexture(r_shadow_bouncegridtexture);
2652 r_shadow_bouncegridtexture = R_LoadTexture3D(r_shadow_texturepool, "bouncegrid", resolution[0], resolution[1], resolution[2], pixels, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, 0, NULL);
2654 r_shadow_bouncegridtime = realtime;
2657 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2659 R_Shadow_RenderMode_Reset();
2660 GL_BlendFunc(GL_ONE, GL_ONE);
2661 GL_DepthRange(0, 1);
2662 GL_DepthTest(r_showshadowvolumes.integer < 2);
2663 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2664 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2665 GL_CullFace(GL_NONE);
2666 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2669 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2671 R_Shadow_RenderMode_Reset();
2672 GL_BlendFunc(GL_ONE, GL_ONE);
2673 GL_DepthRange(0, 1);
2674 GL_DepthTest(r_showlighting.integer < 2);
2675 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2677 GL_DepthFunc(GL_EQUAL);
2678 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2679 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2682 void R_Shadow_RenderMode_End(void)
2684 R_Shadow_RenderMode_Reset();
2685 R_Shadow_RenderMode_ActiveLight(NULL);
2687 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2688 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2691 int bboxedges[12][2] =
2710 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2712 if (!r_shadow_scissor.integer)
2714 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2715 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2716 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2717 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2720 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2721 return true; // invisible
2722 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2723 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2724 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2725 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2726 r_refdef.stats.lights_scissored++;
2730 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2733 const float *vertex3f;
2734 const float *normal3f;
2736 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2737 switch (r_shadow_rendermode)
2739 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2740 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2741 if (VectorLength2(diffusecolor) > 0)
2743 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)
2745 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2746 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2747 if ((dot = DotProduct(n, v)) < 0)
2749 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2750 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2753 VectorCopy(ambientcolor, color4f);
2754 if (r_refdef.fogenabled)
2757 f = RSurf_FogVertex(vertex3f);
2758 VectorScale(color4f, f, color4f);
2765 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2767 VectorCopy(ambientcolor, color4f);
2768 if (r_refdef.fogenabled)
2771 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2772 f = RSurf_FogVertex(vertex3f);
2773 VectorScale(color4f + 4*i, f, color4f);
2779 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2780 if (VectorLength2(diffusecolor) > 0)
2782 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)
2784 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2785 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2787 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2788 if ((dot = DotProduct(n, v)) < 0)
2790 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2791 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2792 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2793 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2797 color4f[0] = ambientcolor[0] * distintensity;
2798 color4f[1] = ambientcolor[1] * distintensity;
2799 color4f[2] = ambientcolor[2] * distintensity;
2801 if (r_refdef.fogenabled)
2804 f = RSurf_FogVertex(vertex3f);
2805 VectorScale(color4f, f, color4f);
2809 VectorClear(color4f);
2815 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2817 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2818 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2820 color4f[0] = ambientcolor[0] * distintensity;
2821 color4f[1] = ambientcolor[1] * distintensity;
2822 color4f[2] = ambientcolor[2] * distintensity;
2823 if (r_refdef.fogenabled)
2826 f = RSurf_FogVertex(vertex3f);
2827 VectorScale(color4f, f, color4f);
2831 VectorClear(color4f);
2836 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2837 if (VectorLength2(diffusecolor) > 0)
2839 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)
2841 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2842 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2844 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2845 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2846 if ((dot = DotProduct(n, v)) < 0)
2848 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2849 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2850 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2851 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2855 color4f[0] = ambientcolor[0] * distintensity;
2856 color4f[1] = ambientcolor[1] * distintensity;
2857 color4f[2] = ambientcolor[2] * distintensity;
2859 if (r_refdef.fogenabled)
2862 f = RSurf_FogVertex(vertex3f);
2863 VectorScale(color4f, f, color4f);
2867 VectorClear(color4f);
2873 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2875 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2876 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2878 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2879 color4f[0] = ambientcolor[0] * distintensity;
2880 color4f[1] = ambientcolor[1] * distintensity;
2881 color4f[2] = ambientcolor[2] * distintensity;
2882 if (r_refdef.fogenabled)
2885 f = RSurf_FogVertex(vertex3f);
2886 VectorScale(color4f, f, color4f);
2890 VectorClear(color4f);
2900 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2902 // used to display how many times a surface is lit for level design purposes
2903 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2904 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2908 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
2910 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2911 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
2912 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2913 GL_DepthFunc(GL_EQUAL);
2915 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2916 GL_DepthFunc(GL_LEQUAL);
2919 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2926 int newnumtriangles;
2930 int maxtriangles = 4096;
2931 static int newelements[4096*3];
2932 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
2933 for (renders = 0;renders < 4;renders++)
2938 newnumtriangles = 0;
2940 // due to low fillrate on the cards this vertex lighting path is
2941 // designed for, we manually cull all triangles that do not
2942 // contain a lit vertex
2943 // this builds batches of triangles from multiple surfaces and
2944 // renders them at once
2945 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2947 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
2949 if (newnumtriangles)
2951 newfirstvertex = min(newfirstvertex, e[0]);
2952 newlastvertex = max(newlastvertex, e[0]);
2956 newfirstvertex = e[0];
2957 newlastvertex = e[0];
2959 newfirstvertex = min(newfirstvertex, e[1]);
2960 newlastvertex = max(newlastvertex, e[1]);
2961 newfirstvertex = min(newfirstvertex, e[2]);
2962 newlastvertex = max(newlastvertex, e[2]);
2968 if (newnumtriangles >= maxtriangles)
2970 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2971 newnumtriangles = 0;
2977 if (newnumtriangles >= 1)
2979 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2982 // if we couldn't find any lit triangles, exit early
2985 // now reduce the intensity for the next overbright pass
2986 // we have to clamp to 0 here incase the drivers have improper
2987 // handling of negative colors
2988 // (some old drivers even have improper handling of >1 color)
2990 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2992 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2994 c[0] = max(0, c[0] - 1);
2995 c[1] = max(0, c[1] - 1);
2996 c[2] = max(0, c[2] - 1);
3008 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
3010 // OpenGL 1.1 path (anything)
3011 float ambientcolorbase[3], diffusecolorbase[3];
3012 float ambientcolorpants[3], diffusecolorpants[3];
3013 float ambientcolorshirt[3], diffusecolorshirt[3];
3014 const float *surfacecolor = rsurface.texture->dlightcolor;
3015 const float *surfacepants = rsurface.colormap_pantscolor;
3016 const float *surfaceshirt = rsurface.colormap_shirtcolor;
3017 rtexture_t *basetexture = rsurface.texture->basetexture;
3018 rtexture_t *pantstexture = rsurface.texture->pantstexture;
3019 rtexture_t *shirttexture = rsurface.texture->shirttexture;
3020 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3021 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3022 ambientscale *= 2 * r_refdef.view.colorscale;
3023 diffusescale *= 2 * r_refdef.view.colorscale;
3024 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3025 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3026 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3027 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3028 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3029 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
3030 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3031 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
3032 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3033 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
3034 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
3035 R_Mesh_TexBind(0, basetexture);
3036 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
3037 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
3038 switch(r_shadow_rendermode)
3040 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3041 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
3042 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3043 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3044 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3046 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3047 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
3048 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
3049 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
3050 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3052 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3053 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
3054 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3055 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3056 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3058 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3063 //R_Mesh_TexBind(0, basetexture);
3064 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
3067 R_Mesh_TexBind(0, pantstexture);
3068 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
3072 R_Mesh_TexBind(0, shirttexture);
3073 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
3077 extern cvar_t gl_lightmaps;
3078 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3080 float ambientscale, diffusescale, specularscale;
3082 float lightcolor[3];
3083 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
3084 ambientscale = rsurface.rtlight->ambientscale;
3085 diffusescale = rsurface.rtlight->diffusescale;
3086 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3087 if (!r_shadow_usenormalmap.integer)
3089 ambientscale += 1.0f * diffusescale;
3093 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
3095 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
3098 VectorNegate(lightcolor, lightcolor);
3099 switch(vid.renderpath)
3101 case RENDERPATH_GL11:
3102 case RENDERPATH_GL13:
3103 case RENDERPATH_GL20:
3104 case RENDERPATH_GLES2:
3105 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
3107 case RENDERPATH_D3D9:
3109 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
3112 case RENDERPATH_D3D10:
3113 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3115 case RENDERPATH_D3D11:
3116 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3118 case RENDERPATH_SOFT:
3119 DPSOFTRAST_BlendSubtract(true);
3123 RSurf_SetupDepthAndCulling();
3124 switch (r_shadow_rendermode)
3126 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3127 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3128 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
3130 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3131 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
3133 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3134 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3135 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3136 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3137 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
3140 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3145 switch(vid.renderpath)
3147 case RENDERPATH_GL11:
3148 case RENDERPATH_GL13:
3149 case RENDERPATH_GL20:
3150 case RENDERPATH_GLES2:
3151 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
3153 case RENDERPATH_D3D9:
3155 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
3158 case RENDERPATH_D3D10:
3159 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3161 case RENDERPATH_D3D11:
3162 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3164 case RENDERPATH_SOFT:
3165 DPSOFTRAST_BlendSubtract(false);
3171 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)
3173 matrix4x4_t tempmatrix = *matrix;
3174 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3176 // if this light has been compiled before, free the associated data
3177 R_RTLight_Uncompile(rtlight);
3179 // clear it completely to avoid any lingering data
3180 memset(rtlight, 0, sizeof(*rtlight));
3182 // copy the properties
3183 rtlight->matrix_lighttoworld = tempmatrix;
3184 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3185 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3186 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3187 VectorCopy(color, rtlight->color);
3188 rtlight->cubemapname[0] = 0;
3189 if (cubemapname && cubemapname[0])
3190 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3191 rtlight->shadow = shadow;
3192 rtlight->corona = corona;
3193 rtlight->style = style;
3194 rtlight->isstatic = isstatic;
3195 rtlight->coronasizescale = coronasizescale;
3196 rtlight->ambientscale = ambientscale;
3197 rtlight->diffusescale = diffusescale;
3198 rtlight->specularscale = specularscale;
3199 rtlight->flags = flags;
3201 // compute derived data
3202 //rtlight->cullradius = rtlight->radius;
3203 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3204 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3205 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3206 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3207 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3208 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3209 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3212 // compiles rtlight geometry
3213 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3214 void R_RTLight_Compile(rtlight_t *rtlight)
3217 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3218 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3219 entity_render_t *ent = r_refdef.scene.worldentity;
3220 dp_model_t *model = r_refdef.scene.worldmodel;
3221 unsigned char *data;
3224 // compile the light
3225 rtlight->compiled = true;
3226 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3227 rtlight->static_numleafs = 0;
3228 rtlight->static_numleafpvsbytes = 0;
3229 rtlight->static_leaflist = NULL;
3230 rtlight->static_leafpvs = NULL;
3231 rtlight->static_numsurfaces = 0;
3232 rtlight->static_surfacelist = NULL;
3233 rtlight->static_shadowmap_receivers = 0x3F;
3234 rtlight->static_shadowmap_casters = 0x3F;
3235 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3236 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3237 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3238 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3239 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3240 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3242 if (model && model->GetLightInfo)
3244 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3245 r_shadow_compilingrtlight = rtlight;
3246 R_FrameData_SetMark();
3247 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);
3248 R_FrameData_ReturnToMark();
3249 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3250 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3251 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3252 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3253 rtlight->static_numsurfaces = numsurfaces;
3254 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3255 rtlight->static_numleafs = numleafs;
3256 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3257 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3258 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3259 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3260 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3261 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3262 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3263 if (rtlight->static_numsurfaces)
3264 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3265 if (rtlight->static_numleafs)
3266 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3267 if (rtlight->static_numleafpvsbytes)
3268 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3269 if (rtlight->static_numshadowtrispvsbytes)
3270 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3271 if (rtlight->static_numlighttrispvsbytes)
3272 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3273 R_FrameData_SetMark();
3274 switch (rtlight->shadowmode)
3276 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3277 if (model->CompileShadowMap && rtlight->shadow)
3278 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3281 if (model->CompileShadowVolume && rtlight->shadow)
3282 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3285 R_FrameData_ReturnToMark();
3286 // now we're done compiling the rtlight
3287 r_shadow_compilingrtlight = NULL;
3291 // use smallest available cullradius - box radius or light radius
3292 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3293 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3295 shadowzpasstris = 0;
3296 if (rtlight->static_meshchain_shadow_zpass)
3297 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3298 shadowzpasstris += mesh->numtriangles;
3300 shadowzfailtris = 0;
3301 if (rtlight->static_meshchain_shadow_zfail)
3302 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3303 shadowzfailtris += mesh->numtriangles;
3306 if (rtlight->static_numlighttrispvsbytes)
3307 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3308 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3312 if (rtlight->static_numlighttrispvsbytes)
3313 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3314 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3317 if (developer_extra.integer)
3318 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);
3321 void R_RTLight_Uncompile(rtlight_t *rtlight)
3323 if (rtlight->compiled)
3325 if (rtlight->static_meshchain_shadow_zpass)
3326 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3327 rtlight->static_meshchain_shadow_zpass = NULL;
3328 if (rtlight->static_meshchain_shadow_zfail)
3329 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3330 rtlight->static_meshchain_shadow_zfail = NULL;
3331 if (rtlight->static_meshchain_shadow_shadowmap)
3332 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3333 rtlight->static_meshchain_shadow_shadowmap = NULL;
3334 // these allocations are grouped
3335 if (rtlight->static_surfacelist)
3336 Mem_Free(rtlight->static_surfacelist);
3337 rtlight->static_numleafs = 0;
3338 rtlight->static_numleafpvsbytes = 0;
3339 rtlight->static_leaflist = NULL;
3340 rtlight->static_leafpvs = NULL;
3341 rtlight->static_numsurfaces = 0;
3342 rtlight->static_surfacelist = NULL;
3343 rtlight->static_numshadowtrispvsbytes = 0;
3344 rtlight->static_shadowtrispvs = NULL;
3345 rtlight->static_numlighttrispvsbytes = 0;
3346 rtlight->static_lighttrispvs = NULL;
3347 rtlight->compiled = false;
3351 void R_Shadow_UncompileWorldLights(void)
3355 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3356 for (lightindex = 0;lightindex < range;lightindex++)
3358 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3361 R_RTLight_Uncompile(&light->rtlight);
3365 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3369 // reset the count of frustum planes
3370 // see rtlight->cached_frustumplanes definition for how much this array
3372 rtlight->cached_numfrustumplanes = 0;
3374 // haven't implemented a culling path for ortho rendering
3375 if (!r_refdef.view.useperspective)
3377 // check if the light is on screen and copy the 4 planes if it is
3378 for (i = 0;i < 4;i++)
3379 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3382 for (i = 0;i < 4;i++)
3383 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3388 // generate a deformed frustum that includes the light origin, this is
3389 // used to cull shadow casting surfaces that can not possibly cast a
3390 // shadow onto the visible light-receiving surfaces, which can be a
3393 // if the light origin is onscreen the result will be 4 planes exactly
3394 // if the light origin is offscreen on only one axis the result will
3395 // be exactly 5 planes (split-side case)
3396 // if the light origin is offscreen on two axes the result will be
3397 // exactly 4 planes (stretched corner case)
3398 for (i = 0;i < 4;i++)
3400 // quickly reject standard frustum planes that put the light
3401 // origin outside the frustum
3402 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3405 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3407 // if all the standard frustum planes were accepted, the light is onscreen
3408 // otherwise we need to generate some more planes below...
3409 if (rtlight->cached_numfrustumplanes < 4)
3411 // at least one of the stock frustum planes failed, so we need to
3412 // create one or two custom planes to enclose the light origin
3413 for (i = 0;i < 4;i++)
3415 // create a plane using the view origin and light origin, and a
3416 // single point from the frustum corner set
3417 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3418 VectorNormalize(plane.normal);
3419 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3420 // see if this plane is backwards and flip it if so
3421 for (j = 0;j < 4;j++)
3422 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3426 VectorNegate(plane.normal, plane.normal);
3428 // flipped plane, test again to see if it is now valid
3429 for (j = 0;j < 4;j++)
3430 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3432 // if the plane is still not valid, then it is dividing the
3433 // frustum and has to be rejected
3437 // we have created a valid plane, compute extra info
3438 PlaneClassify(&plane);
3440 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3442 // if we've found 5 frustum planes then we have constructed a
3443 // proper split-side case and do not need to keep searching for
3444 // planes to enclose the light origin
3445 if (rtlight->cached_numfrustumplanes == 5)
3453 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3455 plane = rtlight->cached_frustumplanes[i];
3456 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));
3461 // now add the light-space box planes if the light box is rotated, as any
3462 // caster outside the oriented light box is irrelevant (even if it passed
3463 // the worldspace light box, which is axial)
3464 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3466 for (i = 0;i < 6;i++)
3470 v[i >> 1] = (i & 1) ? -1 : 1;
3471 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3472 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3473 plane.dist = VectorNormalizeLength(plane.normal);
3474 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3475 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3481 // add the world-space reduced box planes
3482 for (i = 0;i < 6;i++)
3484 VectorClear(plane.normal);
3485 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3486 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3487 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3496 // reduce all plane distances to tightly fit the rtlight cull box, which
3498 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3499 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3500 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3501 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3502 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3503 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3504 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3505 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3506 oldnum = rtlight->cached_numfrustumplanes;
3507 rtlight->cached_numfrustumplanes = 0;
3508 for (j = 0;j < oldnum;j++)
3510 // find the nearest point on the box to this plane
3511 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3512 for (i = 1;i < 8;i++)
3514 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3515 if (bestdist > dist)
3518 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);
3519 // if the nearest point is near or behind the plane, we want this
3520 // plane, otherwise the plane is useless as it won't cull anything
3521 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3523 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3524 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3531 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3535 RSurf_ActiveWorldEntity();
3537 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3540 GL_CullFace(GL_NONE);
3541 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3542 for (;mesh;mesh = mesh->next)
3544 if (!mesh->sidetotals[r_shadow_shadowmapside])
3546 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3547 if (mesh->vertex3fbuffer)
3548 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3550 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3551 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);
3555 else if (r_refdef.scene.worldentity->model)
3556 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);
3558 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3561 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3563 qboolean zpass = false;
3566 int surfacelistindex;
3567 msurface_t *surface;
3569 // if triangle neighbors are disabled, shadowvolumes are disabled
3570 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
3573 RSurf_ActiveWorldEntity();
3575 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3578 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3580 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3581 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3583 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3584 for (;mesh;mesh = mesh->next)
3586 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3587 if (mesh->vertex3fbuffer)
3588 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3590 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3591 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3593 // increment stencil if frontface is infront of depthbuffer
3594 GL_CullFace(r_refdef.view.cullface_back);
3595 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3596 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);
3597 // decrement stencil if backface is infront of depthbuffer
3598 GL_CullFace(r_refdef.view.cullface_front);
3599 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3601 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3603 // decrement stencil if backface is behind depthbuffer
3604 GL_CullFace(r_refdef.view.cullface_front);
3605 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3606 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);
3607 // increment stencil if frontface is behind depthbuffer
3608 GL_CullFace(r_refdef.view.cullface_back);
3609 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3611 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);
3615 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3617 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3618 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3619 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3621 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3622 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3623 if (CHECKPVSBIT(trispvs, t))
3624 shadowmarklist[numshadowmark++] = t;
3626 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);
3628 else if (numsurfaces)
3630 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);
3633 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3636 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3638 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3639 vec_t relativeshadowradius;
3640 RSurf_ActiveModelEntity(ent, false, false, false);
3641 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3642 // we need to re-init the shader for each entity because the matrix changed
3643 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3644 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3645 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3646 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3647 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3648 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3649 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3650 switch (r_shadow_rendermode)
3652 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3653 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3656 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3659 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3662 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3664 // set up properties for rendering light onto this entity
3665 RSurf_ActiveModelEntity(ent, true, true, false);
3666 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3667 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3668 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3669 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3672 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3674 if (!r_refdef.scene.worldmodel->DrawLight)
3677 // set up properties for rendering light onto this entity
3678 RSurf_ActiveWorldEntity();
3679 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3680 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3681 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3682 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3684 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3686 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3689 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3691 dp_model_t *model = ent->model;
3692 if (!model->DrawLight)
3695 R_Shadow_SetupEntityLight(ent);
3697 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3699 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3702 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3706 int numleafs, numsurfaces;
3707 int *leaflist, *surfacelist;
3708 unsigned char *leafpvs;
3709 unsigned char *shadowtrispvs;
3710 unsigned char *lighttrispvs;
3711 //unsigned char *surfacesides;
3712 int numlightentities;
3713 int numlightentities_noselfshadow;
3714 int numshadowentities;
3715 int numshadowentities_noselfshadow;
3716 static entity_render_t *lightentities[MAX_EDICTS];
3717 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3718 static entity_render_t *shadowentities[MAX_EDICTS];
3719 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3722 rtlight->draw = false;
3724 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3725 // skip lights that are basically invisible (color 0 0 0)
3726 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3728 // loading is done before visibility checks because loading should happen
3729 // all at once at the start of a level, not when it stalls gameplay.
3730 // (especially important to benchmarks)
3732 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3734 if (rtlight->compiled)
3735 R_RTLight_Uncompile(rtlight);
3736 R_RTLight_Compile(rtlight);
3740 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3742 // look up the light style value at this time
3743 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3744 VectorScale(rtlight->color, f, rtlight->currentcolor);
3746 if (rtlight->selected)
3748 f = 2 + sin(realtime * M_PI * 4.0);
3749 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3753 // if lightstyle is currently off, don't draw the light
3754 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3757 // skip processing on corona-only lights
3761 // if the light box is offscreen, skip it
3762 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3765 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3766 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3768 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3770 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3772 // compiled light, world available and can receive realtime lighting
3773 // retrieve leaf information
3774 numleafs = rtlight->static_numleafs;
3775 leaflist = rtlight->static_leaflist;
3776 leafpvs = rtlight->static_leafpvs;
3777 numsurfaces = rtlight->static_numsurfaces;
3778 surfacelist = rtlight->static_surfacelist;
3779 //surfacesides = NULL;
3780 shadowtrispvs = rtlight->static_shadowtrispvs;
3781 lighttrispvs = rtlight->static_lighttrispvs;
3783 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3785 // dynamic light, world available and can receive realtime lighting
3786 // calculate lit surfaces and leafs
3787 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);
3788 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3789 leaflist = r_shadow_buffer_leaflist;
3790 leafpvs = r_shadow_buffer_leafpvs;
3791 surfacelist = r_shadow_buffer_surfacelist;
3792 //surfacesides = r_shadow_buffer_surfacesides;
3793 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3794 lighttrispvs = r_shadow_buffer_lighttrispvs;
3795 // if the reduced leaf bounds are offscreen, skip it
3796 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3807 //surfacesides = NULL;
3808 shadowtrispvs = NULL;
3809 lighttrispvs = NULL;
3811 // check if light is illuminating any visible leafs
3814 for (i = 0;i < numleafs;i++)
3815 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3821 // make a list of lit entities and shadow casting entities
3822 numlightentities = 0;
3823 numlightentities_noselfshadow = 0;
3824 numshadowentities = 0;
3825 numshadowentities_noselfshadow = 0;
3827 // add dynamic entities that are lit by the light
3828 for (i = 0;i < r_refdef.scene.numentities;i++)
3831 entity_render_t *ent = r_refdef.scene.entities[i];
3833 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3835 // skip the object entirely if it is not within the valid
3836 // shadow-casting region (which includes the lit region)
3837 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3839 if (!(model = ent->model))
3841 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3843 // this entity wants to receive light, is visible, and is
3844 // inside the light box
3845 // TODO: check if the surfaces in the model can receive light
3846 // so now check if it's in a leaf seen by the light
3847 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))
3849 if (ent->flags & RENDER_NOSELFSHADOW)
3850 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3852 lightentities[numlightentities++] = ent;
3853 // since it is lit, it probably also casts a shadow...
3854 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3855 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3856 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3858 // note: exterior models without the RENDER_NOSELFSHADOW
3859 // flag still create a RENDER_NOSELFSHADOW shadow but
3860 // are lit normally, this means that they are
3861 // self-shadowing but do not shadow other
3862 // RENDER_NOSELFSHADOW entities such as the gun
3863 // (very weird, but keeps the player shadow off the gun)
3864 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3865 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3867 shadowentities[numshadowentities++] = ent;
3870 else if (ent->flags & RENDER_SHADOW)
3872 // this entity is not receiving light, but may still need to
3874 // TODO: check if the surfaces in the model can cast shadow
3875 // now check if it is in a leaf seen by the light
3876 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))
3878 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3879 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3880 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3882 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3883 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3885 shadowentities[numshadowentities++] = ent;
3890 // return if there's nothing at all to light
3891 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3894 // count this light in the r_speeds
3895 r_refdef.stats.lights++;
3897 // flag it as worth drawing later
3898 rtlight->draw = true;
3900 // cache all the animated entities that cast a shadow but are not visible
3901 for (i = 0;i < numshadowentities;i++)
3902 if (!shadowentities[i]->animcache_vertex3f)
3903 R_AnimCache_GetEntity(shadowentities[i], false, false);
3904 for (i = 0;i < numshadowentities_noselfshadow;i++)
3905 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3906 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3908 // allocate some temporary memory for rendering this light later in the frame
3909 // reusable buffers need to be copied, static data can be used as-is
3910 rtlight->cached_numlightentities = numlightentities;
3911 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3912 rtlight->cached_numshadowentities = numshadowentities;
3913 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3914 rtlight->cached_numsurfaces = numsurfaces;
3915 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3916 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3917 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3918 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3919 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3921 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3922 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3923 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3924 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3925 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3929 // compiled light data
3930 rtlight->cached_shadowtrispvs = shadowtrispvs;
3931 rtlight->cached_lighttrispvs = lighttrispvs;
3932 rtlight->cached_surfacelist = surfacelist;
3936 void R_Shadow_DrawLight(rtlight_t *rtlight)
3940 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3941 int numlightentities;
3942 int numlightentities_noselfshadow;
3943 int numshadowentities;
3944 int numshadowentities_noselfshadow;
3945 entity_render_t **lightentities;
3946 entity_render_t **lightentities_noselfshadow;
3947 entity_render_t **shadowentities;
3948 entity_render_t **shadowentities_noselfshadow;
3950 static unsigned char entitysides[MAX_EDICTS];
3951 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3952 vec3_t nearestpoint;
3954 qboolean castshadows;
3957 // check if we cached this light this frame (meaning it is worth drawing)
3961 numlightentities = rtlight->cached_numlightentities;
3962 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3963 numshadowentities = rtlight->cached_numshadowentities;
3964 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3965 numsurfaces = rtlight->cached_numsurfaces;
3966 lightentities = rtlight->cached_lightentities;
3967 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3968 shadowentities = rtlight->cached_shadowentities;
3969 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3970 shadowtrispvs = rtlight->cached_shadowtrispvs;
3971 lighttrispvs = rtlight->cached_lighttrispvs;
3972 surfacelist = rtlight->cached_surfacelist;
3974 // set up a scissor rectangle for this light
3975 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3978 // don't let sound skip if going slow
3979 if (r_refdef.scene.extraupdate)
3982 // make this the active rtlight for rendering purposes
3983 R_Shadow_RenderMode_ActiveLight(rtlight);
3985 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3987 // optionally draw visible shape of the shadow volumes
3988 // for performance analysis by level designers
3989 R_Shadow_RenderMode_VisibleShadowVolumes();
3991 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3992 for (i = 0;i < numshadowentities;i++)
3993 R_Shadow_DrawEntityShadow(shadowentities[i]);
3994 for (i = 0;i < numshadowentities_noselfshadow;i++)
3995 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3996 R_Shadow_RenderMode_VisibleLighting(false, false);
3999 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4001 // optionally draw the illuminated areas
4002 // for performance analysis by level designers
4003 R_Shadow_RenderMode_VisibleLighting(false, false);
4005 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4006 for (i = 0;i < numlightentities;i++)
4007 R_Shadow_DrawEntityLight(lightentities[i]);
4008 for (i = 0;i < numlightentities_noselfshadow;i++)
4009 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4012 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4014 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4015 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4016 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4017 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4019 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
4020 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4021 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4023 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4029 int receivermask = 0;
4030 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4031 Matrix4x4_Abs(&radiustolight);
4033 r_shadow_shadowmaplod = 0;
4034 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4035 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
4036 r_shadow_shadowmaplod = i;
4038 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4040 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4042 surfacesides = NULL;
4045 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4047 castermask = rtlight->static_shadowmap_casters;
4048 receivermask = rtlight->static_shadowmap_receivers;
4052 surfacesides = r_shadow_buffer_surfacesides;
4053 for(i = 0;i < numsurfaces;i++)
4055 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4056 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4057 castermask |= surfacesides[i];
4058 receivermask |= surfacesides[i];
4062 if (receivermask < 0x3F)
4064 for (i = 0;i < numlightentities;i++)
4065 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4066 if (receivermask < 0x3F)
4067 for(i = 0; i < numlightentities_noselfshadow;i++)
4068 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4071 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4075 for (i = 0;i < numshadowentities;i++)
4076 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4077 for (i = 0;i < numshadowentities_noselfshadow;i++)
4078 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4081 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4083 // render shadow casters into 6 sided depth texture
4084 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4086 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
4087 if (! (castermask & (1 << side))) continue;
4089 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4090 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4091 R_Shadow_DrawEntityShadow(shadowentities[i]);
4094 if (numlightentities_noselfshadow)
4096 // render lighting using the depth texture as shadowmap
4097 // draw lighting in the unmasked areas
4098 R_Shadow_RenderMode_Lighting(false, false, true);
4099 for (i = 0;i < numlightentities_noselfshadow;i++)
4100 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4103 // render shadow casters into 6 sided depth texture
4104 if (numshadowentities_noselfshadow)
4106 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4108 R_Shadow_RenderMode_ShadowMap(side, 0, size);
4109 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
4110 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4114 // render lighting using the depth texture as shadowmap
4115 // draw lighting in the unmasked areas
4116 R_Shadow_RenderMode_Lighting(false, false, true);
4117 // draw lighting in the unmasked areas
4119 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4120 for (i = 0;i < numlightentities;i++)
4121 R_Shadow_DrawEntityLight(lightentities[i]);
4123 else if (castshadows && vid.stencil)
4125 // draw stencil shadow volumes to mask off pixels that are in shadow
4126 // so that they won't receive lighting
4127 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4128 R_Shadow_ClearStencil();
4131 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4132 for (i = 0;i < numshadowentities;i++)
4133 R_Shadow_DrawEntityShadow(shadowentities[i]);
4135 // draw lighting in the unmasked areas
4136 R_Shadow_RenderMode_Lighting(true, false, false);
4137 for (i = 0;i < numlightentities_noselfshadow;i++)
4138 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4140 for (i = 0;i < numshadowentities_noselfshadow;i++)
4141 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4143 // draw lighting in the unmasked areas
4144 R_Shadow_RenderMode_Lighting(true, false, false);
4146 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4147 for (i = 0;i < numlightentities;i++)
4148 R_Shadow_DrawEntityLight(lightentities[i]);
4152 // draw lighting in the unmasked areas
4153 R_Shadow_RenderMode_Lighting(false, false, false);
4155 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4156 for (i = 0;i < numlightentities;i++)
4157 R_Shadow_DrawEntityLight(lightentities[i]);
4158 for (i = 0;i < numlightentities_noselfshadow;i++)
4159 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4162 if (r_shadow_usingdeferredprepass)
4164 // when rendering deferred lighting, we simply rasterize the box
4165 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4166 R_Shadow_RenderMode_DrawDeferredLight(false, true);
4167 else if (castshadows && vid.stencil)
4168 R_Shadow_RenderMode_DrawDeferredLight(true, false);
4170 R_Shadow_RenderMode_DrawDeferredLight(false, false);
4174 static void R_Shadow_FreeDeferred(void)
4176 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
4177 r_shadow_prepassgeometryfbo = 0;
4179 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
4180 r_shadow_prepasslightingdiffusespecularfbo = 0;
4182 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
4183 r_shadow_prepasslightingdiffusefbo = 0;
4185 if (r_shadow_prepassgeometrydepthtexture)
4186 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
4187 r_shadow_prepassgeometrydepthtexture = NULL;
4189 if (r_shadow_prepassgeometrydepthcolortexture)
4190 R_FreeTexture(r_shadow_prepassgeometrydepthcolortexture);
4191 r_shadow_prepassgeometrydepthcolortexture = NULL;
4193 if (r_shadow_prepassgeometrynormalmaptexture)
4194 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4195 r_shadow_prepassgeometrynormalmaptexture = NULL;
4197 if (r_shadow_prepasslightingdiffusetexture)
4198 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
4199 r_shadow_prepasslightingdiffusetexture = NULL;
4201 if (r_shadow_prepasslightingspeculartexture)
4202 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4203 r_shadow_prepasslightingspeculartexture = NULL;
4206 void R_Shadow_DrawPrepass(void)
4214 entity_render_t *ent;
4215 float clearcolor[4];
4217 R_Mesh_ResetTextureState();
4219 GL_ColorMask(1,1,1,1);
4220 GL_BlendFunc(GL_ONE, GL_ZERO);
4223 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4224 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4225 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4226 if (r_timereport_active)
4227 R_TimeReport("prepasscleargeom");
4229 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4230 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4231 if (r_timereport_active)
4232 R_TimeReport("prepassworld");
4234 for (i = 0;i < r_refdef.scene.numentities;i++)
4236 if (!r_refdef.viewcache.entityvisible[i])
4238 ent = r_refdef.scene.entities[i];
4239 if (ent->model && ent->model->DrawPrepass != NULL)
4240 ent->model->DrawPrepass(ent);
4243 if (r_timereport_active)
4244 R_TimeReport("prepassmodels");
4246 GL_DepthMask(false);
4247 GL_ColorMask(1,1,1,1);
4250 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4251 Vector4Set(clearcolor, 0, 0, 0, 0);
4252 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4253 if (r_timereport_active)
4254 R_TimeReport("prepassclearlit");
4256 R_Shadow_RenderMode_Begin();
4258 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4259 if (r_shadow_debuglight.integer >= 0)
4261 lightindex = r_shadow_debuglight.integer;
4262 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4263 if (light && (light->flags & flag) && light->rtlight.draw)
4264 R_Shadow_DrawLight(&light->rtlight);
4268 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4269 for (lightindex = 0;lightindex < range;lightindex++)
4271 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4272 if (light && (light->flags & flag) && light->rtlight.draw)
4273 R_Shadow_DrawLight(&light->rtlight);
4276 if (r_refdef.scene.rtdlight)
4277 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4278 if (r_refdef.scene.lights[lnum]->draw)
4279 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4281 R_Mesh_ResetRenderTargets();
4283 R_Shadow_RenderMode_End();
4285 if (r_timereport_active)
4286 R_TimeReport("prepasslights");
4289 void R_Shadow_DrawLightSprites(void);
4290 void R_Shadow_PrepareLights(void)
4300 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4301 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4302 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
4303 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4304 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4305 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4306 R_Shadow_FreeShadowMaps();
4308 r_shadow_usingshadowmaportho = false;
4310 switch (vid.renderpath)
4312 case RENDERPATH_GL20:
4313 case RENDERPATH_D3D9:
4314 case RENDERPATH_D3D10:
4315 case RENDERPATH_D3D11:
4316 case RENDERPATH_SOFT:
4317 case RENDERPATH_GLES2:
4318 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4320 r_shadow_usingdeferredprepass = false;
4321 if (r_shadow_prepass_width)
4322 R_Shadow_FreeDeferred();
4323 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4327 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4329 R_Shadow_FreeDeferred();
4331 r_shadow_usingdeferredprepass = true;
4332 r_shadow_prepass_width = vid.width;
4333 r_shadow_prepass_height = vid.height;
4334 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4335 switch (vid.renderpath)
4337 case RENDERPATH_D3D9:
4338 r_shadow_prepassgeometrydepthcolortexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrydepthcolormap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4343 r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4344 r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4345 r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4347 // set up the geometry pass fbo (depth + normalmap)
4348 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4349 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4350 // render depth into one texture and normalmap into the other
4351 if (qglDrawBuffersARB)
4353 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4354 qglReadBuffer(GL_NONE);CHECKGLERROR
4355 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4356 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4358 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4359 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4360 r_shadow_usingdeferredprepass = false;
4364 // set up the lighting pass fbo (diffuse + specular)
4365 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4366 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4367 // render diffuse into one texture and specular into another,
4368 // with depth and normalmap bound as textures,
4369 // with depth bound as attachment as well
4370 if (qglDrawBuffersARB)
4372 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4373 qglReadBuffer(GL_NONE);CHECKGLERROR
4374 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4375 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4377 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4378 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4379 r_shadow_usingdeferredprepass = false;
4383 // set up the lighting pass fbo (diffuse)
4384 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4385 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4386 // render diffuse into one texture,
4387 // with depth and normalmap bound as textures,
4388 // with depth bound as attachment as well
4389 if (qglDrawBuffersARB)
4391 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4392 qglReadBuffer(GL_NONE);CHECKGLERROR
4393 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4394 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4396 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4397 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4398 r_shadow_usingdeferredprepass = false;
4403 case RENDERPATH_GL13:
4404 case RENDERPATH_GL11:
4405 r_shadow_usingdeferredprepass = false;
4409 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);
4411 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4412 if (r_shadow_debuglight.integer >= 0)
4414 lightindex = r_shadow_debuglight.integer;
4415 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4416 if (light && (light->flags & flag))
4417 R_Shadow_PrepareLight(&light->rtlight);
4421 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4422 for (lightindex = 0;lightindex < range;lightindex++)
4424 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4425 if (light && (light->flags & flag))
4426 R_Shadow_PrepareLight(&light->rtlight);
4429 if (r_refdef.scene.rtdlight)
4431 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4432 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4434 else if(gl_flashblend.integer)
4436 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4438 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4439 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4440 VectorScale(rtlight->color, f, rtlight->currentcolor);
4444 if (r_editlights.integer)
4445 R_Shadow_DrawLightSprites();
4447 R_Shadow_UpdateBounceGridTexture();
4450 void R_Shadow_DrawLights(void)
4458 R_Shadow_RenderMode_Begin();
4460 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4461 if (r_shadow_debuglight.integer >= 0)
4463 lightindex = r_shadow_debuglight.integer;
4464 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4465 if (light && (light->flags & flag))
4466 R_Shadow_DrawLight(&light->rtlight);
4470 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4471 for (lightindex = 0;lightindex < range;lightindex++)
4473 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4474 if (light && (light->flags & flag))
4475 R_Shadow_DrawLight(&light->rtlight);
4478 if (r_refdef.scene.rtdlight)
4479 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4480 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4482 R_Shadow_RenderMode_End();
4485 extern const float r_screenvertex3f[12];
4486 extern void R_SetupView(qboolean allowwaterclippingplane);
4487 extern void R_ResetViewRendering3D(void);
4488 extern void R_ResetViewRendering2D(void);
4489 extern cvar_t r_shadows;
4490 extern cvar_t r_shadows_darken;
4491 extern cvar_t r_shadows_drawafterrtlighting;
4492 extern cvar_t r_shadows_castfrombmodels;
4493 extern cvar_t r_shadows_throwdistance;
4494 extern cvar_t r_shadows_throwdirection;
4495 extern cvar_t r_shadows_focus;
4496 extern cvar_t r_shadows_shadowmapscale;
4498 void R_Shadow_PrepareModelShadows(void)
4501 float scale, size, radius, dot1, dot2;
4502 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4503 entity_render_t *ent;
4505 if (!r_refdef.scene.numentities)
4508 switch (r_shadow_shadowmode)
4510 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4511 if (r_shadows.integer >= 2)
4514 case R_SHADOW_SHADOWMODE_STENCIL:
4515 for (i = 0;i < r_refdef.scene.numentities;i++)
4517 ent = r_refdef.scene.entities[i];
4518 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4519 R_AnimCache_GetEntity(ent, false, false);
4526 size = 2*r_shadow_shadowmapmaxsize;
4527 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4528 radius = 0.5f * size / scale;
4530 Math_atov(r_shadows_throwdirection.string, shadowdir);
4531 VectorNormalize(shadowdir);
4532 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4533 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4534 if (fabs(dot1) <= fabs(dot2))
4535 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4537 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4538 VectorNormalize(shadowforward);
4539 CrossProduct(shadowdir, shadowforward, shadowright);
4540 Math_atov(r_shadows_focus.string, shadowfocus);
4541 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4542 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4543 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4544 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4545 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4547 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4549 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4550 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4551 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4552 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4553 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4554 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4556 for (i = 0;i < r_refdef.scene.numentities;i++)
4558 ent = r_refdef.scene.entities[i];
4559 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4561 // cast shadows from anything of the map (submodels are optional)
4562 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4563 R_AnimCache_GetEntity(ent, false, false);
4567 void R_DrawModelShadowMaps(void)
4570 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4571 entity_render_t *ent;
4572 vec3_t relativelightorigin;
4573 vec3_t relativelightdirection, relativeforward, relativeright;
4574 vec3_t relativeshadowmins, relativeshadowmaxs;
4575 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4577 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4578 r_viewport_t viewport;
4580 float clearcolor[4];
4582 if (!r_refdef.scene.numentities)
4585 switch (r_shadow_shadowmode)
4587 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4593 R_ResetViewRendering3D();
4594 R_Shadow_RenderMode_Begin();
4595 R_Shadow_RenderMode_ActiveLight(NULL);
4597 switch (r_shadow_shadowmode)
4599 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4600 if (!r_shadow_shadowmap2dtexture)
4601 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4602 fbo = r_shadow_fbo2d;
4603 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4604 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4605 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4611 size = 2*r_shadow_shadowmapmaxsize;
4612 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4613 radius = 0.5f / scale;
4614 nearclip = -r_shadows_throwdistance.value;
4615 farclip = r_shadows_throwdistance.value;
4616 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4618 r_shadow_shadowmap_parameters[0] = size;
4619 r_shadow_shadowmap_parameters[1] = size;
4620 r_shadow_shadowmap_parameters[2] = 1.0;
4621 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4623 Math_atov(r_shadows_throwdirection.string, shadowdir);
4624 VectorNormalize(shadowdir);
4625 Math_atov(r_shadows_focus.string, shadowfocus);
4626 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4627 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4628 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4629 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4630 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4631 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4632 if (fabs(dot1) <= fabs(dot2))
4633 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4635 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4636 VectorNormalize(shadowforward);
4637 VectorM(scale, shadowforward, &m[0]);
4638 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4640 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4641 CrossProduct(shadowdir, shadowforward, shadowright);
4642 VectorM(scale, shadowright, &m[4]);
4643 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4644 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4645 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4646 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4647 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4648 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4650 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4652 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
4653 R_SetupShader_DepthOrShadow();
4654 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4657 R_SetViewport(&viewport);
4658 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4659 Vector4Set(clearcolor, 1,1,1,1);
4660 // in D3D9 we have to render to a color texture shadowmap
4661 // in GL we render directly to a depth texture only
4662 if (r_shadow_shadowmap2dtexture)
4663 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4665 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4666 // render into a slightly restricted region so that the borders of the
4667 // shadowmap area fade away, rather than streaking across everything
4668 // outside the usable area
4669 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4673 R_Mesh_ResetRenderTargets();
4674 R_SetupShader_ShowDepth();
4675 GL_ColorMask(1,1,1,1);
4676 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4679 for (i = 0;i < r_refdef.scene.numentities;i++)
4681 ent = r_refdef.scene.entities[i];
4683 // cast shadows from anything of the map (submodels are optional)
4684 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4686 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4687 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4688 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4689 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4690 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4691 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4692 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4693 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4694 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4695 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4696 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4697 RSurf_ActiveModelEntity(ent, false, false, false);
4698 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4699 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4706 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4708 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4710 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4711 Cvar_SetValueQuick(&r_test, 0);
4716 R_Shadow_RenderMode_End();
4718 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4719 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4720 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4721 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4722 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4723 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4725 switch (vid.renderpath)
4727 case RENDERPATH_GL11:
4728 case RENDERPATH_GL13:
4729 case RENDERPATH_GL20:
4730 case RENDERPATH_SOFT:
4731 case RENDERPATH_GLES2:
4733 case RENDERPATH_D3D9:
4734 case RENDERPATH_D3D10:
4735 case RENDERPATH_D3D11:
4736 #ifdef OPENGL_ORIENTATION
4737 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4738 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
4739 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
4740 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
4742 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4743 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
4744 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
4745 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
4750 r_shadow_usingshadowmaportho = true;
4751 switch (r_shadow_shadowmode)
4753 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4754 r_shadow_usingshadowmap2d = true;
4761 void R_DrawModelShadows(void)
4764 float relativethrowdistance;
4765 entity_render_t *ent;
4766 vec3_t relativelightorigin;
4767 vec3_t relativelightdirection;
4768 vec3_t relativeshadowmins, relativeshadowmaxs;
4769 vec3_t tmp, shadowdir;
4771 if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4774 R_ResetViewRendering3D();
4775 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4776 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4777 R_Shadow_RenderMode_Begin();
4778 R_Shadow_RenderMode_ActiveLight(NULL);
4779 r_shadow_lightscissor[0] = r_refdef.view.x;
4780 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4781 r_shadow_lightscissor[2] = r_refdef.view.width;
4782 r_shadow_lightscissor[3] = r_refdef.view.height;
4783 R_Shadow_RenderMode_StencilShadowVolumes(false);
4786 if (r_shadows.integer == 2)
4788 Math_atov(r_shadows_throwdirection.string, shadowdir);
4789 VectorNormalize(shadowdir);
4792 R_Shadow_ClearStencil();
4794 for (i = 0;i < r_refdef.scene.numentities;i++)
4796 ent = r_refdef.scene.entities[i];
4798 // cast shadows from anything of the map (submodels are optional)
4799 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4801 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4802 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4803 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4804 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4805 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4808 if(ent->entitynumber != 0)
4810 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4812 // FIXME handle this
4813 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4817 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4818 int entnum, entnum2, recursion;
4819 entnum = entnum2 = ent->entitynumber;
4820 for(recursion = 32; recursion > 0; --recursion)
4822 entnum2 = cl.entities[entnum].state_current.tagentity;
4823 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4828 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4830 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4831 // transform into modelspace of OUR entity
4832 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4833 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4836 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4840 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4843 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4844 RSurf_ActiveModelEntity(ent, false, false, false);
4845 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4846 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4850 // not really the right mode, but this will disable any silly stencil features
4851 R_Shadow_RenderMode_End();
4853 // set up ortho view for rendering this pass
4854 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4855 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4856 //GL_ScissorTest(true);
4857 //R_EntityMatrix(&identitymatrix);
4858 //R_Mesh_ResetTextureState();
4859 R_ResetViewRendering2D();
4861 // set up a darkening blend on shadowed areas
4862 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4863 //GL_DepthRange(0, 1);
4864 //GL_DepthTest(false);
4865 //GL_DepthMask(false);
4866 //GL_PolygonOffset(0, 0);CHECKGLERROR
4867 GL_Color(0, 0, 0, r_shadows_darken.value);
4868 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4869 //GL_DepthFunc(GL_ALWAYS);
4870 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
4872 // apply the blend to the shadowed areas
4873 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
4874 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4875 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4877 // restore the viewport
4878 R_SetViewport(&r_refdef.view.viewport);
4880 // restore other state to normal
4881 //R_Shadow_RenderMode_End();
4884 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4887 vec3_t centerorigin;
4889 // if it's too close, skip it
4890 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4892 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4895 if (usequery && r_numqueries + 2 <= r_maxqueries)
4897 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4898 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4899 // 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
4900 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4902 switch(vid.renderpath)
4904 case RENDERPATH_GL20:
4905 case RENDERPATH_GL13:
4906 case RENDERPATH_GL11:
4907 case RENDERPATH_GLES2:
4909 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4910 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4911 GL_DepthFunc(GL_ALWAYS);
4912 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4913 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
4914 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4915 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4916 GL_DepthFunc(GL_LEQUAL);
4917 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4918 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4919 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
4920 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4921 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4924 case RENDERPATH_D3D9:
4925 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4927 case RENDERPATH_D3D10:
4928 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4930 case RENDERPATH_D3D11:
4931 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4933 case RENDERPATH_SOFT:
4934 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4938 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4941 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4943 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4946 GLint allpixels = 0, visiblepixels = 0;
4947 // now we have to check the query result
4948 if (rtlight->corona_queryindex_visiblepixels)
4950 switch(vid.renderpath)
4952 case RENDERPATH_GL20:
4953 case RENDERPATH_GL13:
4954 case RENDERPATH_GL11:
4955 case RENDERPATH_GLES2:
4957 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4958 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4961 case RENDERPATH_D3D9:
4962 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4964 case RENDERPATH_D3D10:
4965 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4967 case RENDERPATH_D3D11:
4968 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4970 case RENDERPATH_SOFT:
4971 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4974 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4975 if (visiblepixels < 1 || allpixels < 1)
4977 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4978 cscale *= rtlight->corona_visibility;
4982 // FIXME: these traces should scan all render entities instead of cl.world
4983 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1)
4986 VectorScale(rtlight->currentcolor, cscale, color);
4987 if (VectorLength(color) > (1.0f / 256.0f))
4990 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4993 VectorNegate(color, color);
4994 switch(vid.renderpath)
4996 case RENDERPATH_GL11:
4997 case RENDERPATH_GL13:
4998 case RENDERPATH_GL20:
4999 case RENDERPATH_GLES2:
5000 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
5002 case RENDERPATH_D3D9:
5004 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
5007 case RENDERPATH_D3D10:
5008 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5010 case RENDERPATH_D3D11:
5011 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5013 case RENDERPATH_SOFT:
5014 DPSOFTRAST_BlendSubtract(true);
5018 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5019 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);
5020 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5023 switch(vid.renderpath)
5025 case RENDERPATH_GL11:
5026 case RENDERPATH_GL13:
5027 case RENDERPATH_GL20:
5028 case RENDERPATH_GLES2:
5029 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
5031 case RENDERPATH_D3D9:
5033 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
5036 case RENDERPATH_D3D10:
5037 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5039 case RENDERPATH_D3D11:
5040 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5042 case RENDERPATH_SOFT:
5043 DPSOFTRAST_BlendSubtract(false);
5050 void R_Shadow_DrawCoronas(void)
5053 qboolean usequery = false;
5058 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
5060 if (r_waterstate.renderingscene)
5062 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5063 R_EntityMatrix(&identitymatrix);
5065 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5067 // check occlusion of coronas
5068 // use GL_ARB_occlusion_query if available
5069 // otherwise use raytraces
5071 switch (vid.renderpath)
5073 case RENDERPATH_GL11:
5074 case RENDERPATH_GL13:
5075 case RENDERPATH_GL20:
5076 case RENDERPATH_GLES2:
5077 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
5080 GL_ColorMask(0,0,0,0);
5081 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
5082 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
5085 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
5086 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
5088 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
5091 RSurf_ActiveWorldEntity();
5092 GL_BlendFunc(GL_ONE, GL_ZERO);
5093 GL_CullFace(GL_NONE);
5094 GL_DepthMask(false);
5095 GL_DepthRange(0, 1);
5096 GL_PolygonOffset(0, 0);
5098 R_Mesh_ResetTextureState();
5099 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
5102 case RENDERPATH_D3D9:
5104 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5106 case RENDERPATH_D3D10:
5107 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5109 case RENDERPATH_D3D11:
5110 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5112 case RENDERPATH_SOFT:
5114 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5117 for (lightindex = 0;lightindex < range;lightindex++)
5119 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5122 rtlight = &light->rtlight;
5123 rtlight->corona_visibility = 0;
5124 rtlight->corona_queryindex_visiblepixels = 0;
5125 rtlight->corona_queryindex_allpixels = 0;
5126 if (!(rtlight->flags & flag))
5128 if (rtlight->corona <= 0)
5130 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
5132 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5134 for (i = 0;i < r_refdef.scene.numlights;i++)
5136 rtlight = r_refdef.scene.lights[i];
5137 rtlight->corona_visibility = 0;
5138 rtlight->corona_queryindex_visiblepixels = 0;
5139 rtlight->corona_queryindex_allpixels = 0;
5140 if (!(rtlight->flags & flag))
5142 if (rtlight->corona <= 0)
5144 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5147 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5149 // now draw the coronas using the query data for intensity info
5150 for (lightindex = 0;lightindex < range;lightindex++)
5152 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5155 rtlight = &light->rtlight;
5156 if (rtlight->corona_visibility <= 0)
5158 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5160 for (i = 0;i < r_refdef.scene.numlights;i++)
5162 rtlight = r_refdef.scene.lights[i];
5163 if (rtlight->corona_visibility <= 0)
5165 if (gl_flashblend.integer)
5166 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
5168 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5174 dlight_t *R_Shadow_NewWorldLight(void)
5176 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
5179 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)
5182 // validate parameters
5183 if (style < 0 || style >= MAX_LIGHTSTYLES)
5185 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
5191 // copy to light properties
5192 VectorCopy(origin, light->origin);
5193 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
5194 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
5195 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
5197 light->color[0] = max(color[0], 0);
5198 light->color[1] = max(color[1], 0);
5199 light->color[2] = max(color[2], 0);
5201 light->color[0] = color[0];
5202 light->color[1] = color[1];
5203 light->color[2] = color[2];
5204 light->radius = max(radius, 0);
5205 light->style = style;
5206 light->shadow = shadowenable;
5207 light->corona = corona;
5208 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
5209 light->coronasizescale = coronasizescale;
5210 light->ambientscale = ambientscale;
5211 light->diffusescale = diffusescale;
5212 light->specularscale = specularscale;
5213 light->flags = flags;
5215 // update renderable light data
5216 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
5217 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);
5220 void R_Shadow_FreeWorldLight(dlight_t *light)
5222 if (r_shadow_selectedlight == light)
5223 r_shadow_selectedlight = NULL;
5224 R_RTLight_Uncompile(&light->rtlight);
5225 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
5228 void R_Shadow_ClearWorldLights(void)
5232 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5233 for (lightindex = 0;lightindex < range;lightindex++)
5235 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5237 R_Shadow_FreeWorldLight(light);
5239 r_shadow_selectedlight = NULL;
5242 void R_Shadow_SelectLight(dlight_t *light)
5244 if (r_shadow_selectedlight)
5245 r_shadow_selectedlight->selected = false;
5246 r_shadow_selectedlight = light;
5247 if (r_shadow_selectedlight)
5248 r_shadow_selectedlight->selected = true;
5251 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5253 // this is never batched (there can be only one)
5255 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
5256 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5257 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5260 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5265 skinframe_t *skinframe;
5268 // this is never batched (due to the ent parameter changing every time)
5269 // so numsurfaces == 1 and surfacelist[0] == lightnumber
5270 const dlight_t *light = (dlight_t *)ent;
5273 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
5276 VectorScale(light->color, intensity, spritecolor);
5277 if (VectorLength(spritecolor) < 0.1732f)
5278 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
5279 if (VectorLength(spritecolor) > 1.0f)
5280 VectorNormalize(spritecolor);
5282 // draw light sprite
5283 if (light->cubemapname[0] && !light->shadow)
5284 skinframe = r_editlights_sprcubemapnoshadowlight;
5285 else if (light->cubemapname[0])
5286 skinframe = r_editlights_sprcubemaplight;
5287 else if (!light->shadow)
5288 skinframe = r_editlights_sprnoshadowlight;
5290 skinframe = r_editlights_sprlight;
5292 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);
5293 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5295 // draw selection sprite if light is selected
5296 if (light->selected)
5298 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5299 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5300 // VorteX todo: add normalmode/realtime mode light overlay sprites?
5304 void R_Shadow_DrawLightSprites(void)
5308 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5309 for (lightindex = 0;lightindex < range;lightindex++)
5311 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5313 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
5315 if (!r_editlights_lockcursor)
5316 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
5319 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
5324 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
5325 if (lightindex >= range)
5327 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5330 rtlight = &light->rtlight;
5331 //if (!(rtlight->flags & flag))
5333 VectorCopy(rtlight->shadoworigin, origin);
5334 *radius = rtlight->radius;
5335 VectorCopy(rtlight->color, color);
5339 void R_Shadow_SelectLightInView(void)
5341 float bestrating, rating, temp[3];
5345 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5349 if (r_editlights_lockcursor)
5351 for (lightindex = 0;lightindex < range;lightindex++)
5353 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5356 VectorSubtract(light->origin, r_refdef.view.origin, temp);
5357 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
5360 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
5361 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction == 1.0f)
5363 bestrating = rating;
5368 R_Shadow_SelectLight(best);
5371 void R_Shadow_LoadWorldLights(void)
5373 int n, a, style, shadow, flags;
5374 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
5375 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
5376 if (cl.worldmodel == NULL)
5378 Con_Print("No map loaded.\n");
5381 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5382 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5392 for (;COM_Parse(t, true) && strcmp(
5393 if (COM_Parse(t, true))
5395 if (com_token[0] == '!')
5398 origin[0] = atof(com_token+1);
5401 origin[0] = atof(com_token);
5406 while (*s && *s != '\n' && *s != '\r')
5412 // check for modifier flags
5419 #if _MSC_VER >= 1400
5420 #define sscanf sscanf_s
5422 cubemapname[sizeof(cubemapname)-1] = 0;
5423 #if MAX_QPATH != 128
5424 #error update this code if MAX_QPATH changes
5426 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
5427 #if _MSC_VER >= 1400
5428 , sizeof(cubemapname)
5430 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5433 flags = LIGHTFLAG_REALTIMEMODE;
5441 coronasizescale = 0.25f;
5443 VectorClear(angles);
5446 if (a < 9 || !strcmp(cubemapname, "\"\""))
5448 // remove quotes on cubemapname
5449 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5452 namelen = strlen(cubemapname) - 2;
5453 memmove(cubemapname, cubemapname + 1, namelen);
5454 cubemapname[namelen] = '\0';
5458 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);
5461 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5469 Con_Printf("invalid rtlights file \"%s\"\n", name);
5470 Mem_Free(lightsstring);
5474 void R_Shadow_SaveWorldLights(void)
5478 size_t bufchars, bufmaxchars;
5480 char name[MAX_QPATH];
5481 char line[MAX_INPUTLINE];
5482 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5483 // I hate lines which are 3 times my screen size :( --blub
5486 if (cl.worldmodel == NULL)
5488 Con_Print("No map loaded.\n");
5491 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5492 bufchars = bufmaxchars = 0;
5494 for (lightindex = 0;lightindex < range;lightindex++)
5496 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5499 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5500 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);
5501 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5502 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]);
5504 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);
5505 if (bufchars + strlen(line) > bufmaxchars)
5507 bufmaxchars = bufchars + strlen(line) + 2048;
5509 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5513 memcpy(buf, oldbuf, bufchars);
5519 memcpy(buf + bufchars, line, strlen(line));
5520 bufchars += strlen(line);
5524 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5529 void R_Shadow_LoadLightsFile(void)
5532 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5533 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5534 if (cl.worldmodel == NULL)
5536 Con_Print("No map loaded.\n");
5539 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5540 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5548 while (*s && *s != '\n' && *s != '\r')
5554 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);
5558 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);
5561 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5562 radius = bound(15, radius, 4096);
5563 VectorScale(color, (2.0f / (8388608.0f)), color);
5564 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5572 Con_Printf("invalid lights file \"%s\"\n", name);
5573 Mem_Free(lightsstring);
5577 // tyrlite/hmap2 light types in the delay field
5578 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5580 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5592 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5593 char key[256], value[MAX_INPUTLINE];
5595 if (cl.worldmodel == NULL)
5597 Con_Print("No map loaded.\n");
5600 // try to load a .ent file first
5601 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5602 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5603 // and if that is not found, fall back to the bsp file entity string
5605 data = cl.worldmodel->brush.entities;
5608 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5610 type = LIGHTTYPE_MINUSX;
5611 origin[0] = origin[1] = origin[2] = 0;
5612 originhack[0] = originhack[1] = originhack[2] = 0;
5613 angles[0] = angles[1] = angles[2] = 0;
5614 color[0] = color[1] = color[2] = 1;
5615 light[0] = light[1] = light[2] = 1;light[3] = 300;
5616 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5626 if (!COM_ParseToken_Simple(&data, false, false))
5628 if (com_token[0] == '}')
5629 break; // end of entity
5630 if (com_token[0] == '_')
5631 strlcpy(key, com_token + 1, sizeof(key));
5633 strlcpy(key, com_token, sizeof(key));
5634 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5635 key[strlen(key)-1] = 0;
5636 if (!COM_ParseToken_Simple(&data, false, false))
5638 strlcpy(value, com_token, sizeof(value));
5640 // now that we have the key pair worked out...
5641 if (!strcmp("light", key))
5643 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5647 light[0] = vec[0] * (1.0f / 256.0f);
5648 light[1] = vec[0] * (1.0f / 256.0f);
5649 light[2] = vec[0] * (1.0f / 256.0f);
5655 light[0] = vec[0] * (1.0f / 255.0f);
5656 light[1] = vec[1] * (1.0f / 255.0f);
5657 light[2] = vec[2] * (1.0f / 255.0f);
5661 else if (!strcmp("delay", key))
5663 else if (!strcmp("origin", key))
5664 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5665 else if (!strcmp("angle", key))
5666 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5667 else if (!strcmp("angles", key))
5668 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5669 else if (!strcmp("color", key))
5670 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5671 else if (!strcmp("wait", key))
5672 fadescale = atof(value);
5673 else if (!strcmp("classname", key))
5675 if (!strncmp(value, "light", 5))
5678 if (!strcmp(value, "light_fluoro"))
5683 overridecolor[0] = 1;
5684 overridecolor[1] = 1;
5685 overridecolor[2] = 1;
5687 if (!strcmp(value, "light_fluorospark"))
5692 overridecolor[0] = 1;
5693 overridecolor[1] = 1;
5694 overridecolor[2] = 1;
5696 if (!strcmp(value, "light_globe"))
5701 overridecolor[0] = 1;
5702 overridecolor[1] = 0.8;
5703 overridecolor[2] = 0.4;
5705 if (!strcmp(value, "light_flame_large_yellow"))
5710 overridecolor[0] = 1;
5711 overridecolor[1] = 0.5;
5712 overridecolor[2] = 0.1;
5714 if (!strcmp(value, "light_flame_small_yellow"))
5719 overridecolor[0] = 1;
5720 overridecolor[1] = 0.5;
5721 overridecolor[2] = 0.1;
5723 if (!strcmp(value, "light_torch_small_white"))
5728 overridecolor[0] = 1;
5729 overridecolor[1] = 0.5;
5730 overridecolor[2] = 0.1;
5732 if (!strcmp(value, "light_torch_small_walltorch"))
5737 overridecolor[0] = 1;
5738 overridecolor[1] = 0.5;
5739 overridecolor[2] = 0.1;
5743 else if (!strcmp("style", key))
5744 style = atoi(value);
5745 else if (!strcmp("skin", key))
5746 skin = (int)atof(value);
5747 else if (!strcmp("pflags", key))
5748 pflags = (int)atof(value);
5749 //else if (!strcmp("effects", key))
5750 // effects = (int)atof(value);
5751 else if (cl.worldmodel->type == mod_brushq3)
5753 if (!strcmp("scale", key))
5754 lightscale = atof(value);
5755 if (!strcmp("fade", key))
5756 fadescale = atof(value);
5761 if (lightscale <= 0)
5765 if (color[0] == color[1] && color[0] == color[2])
5767 color[0] *= overridecolor[0];
5768 color[1] *= overridecolor[1];
5769 color[2] *= overridecolor[2];
5771 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5772 color[0] = color[0] * light[0];
5773 color[1] = color[1] * light[1];
5774 color[2] = color[2] * light[2];
5777 case LIGHTTYPE_MINUSX:
5779 case LIGHTTYPE_RECIPX:
5781 VectorScale(color, (1.0f / 16.0f), color);
5783 case LIGHTTYPE_RECIPXX:
5785 VectorScale(color, (1.0f / 16.0f), color);
5788 case LIGHTTYPE_NONE:
5792 case LIGHTTYPE_MINUSXX:
5795 VectorAdd(origin, originhack, origin);
5797 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5800 Mem_Free(entfiledata);
5804 void R_Shadow_SetCursorLocationForView(void)
5807 vec3_t dest, endpos;
5809 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5810 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true);
5811 if (trace.fraction < 1)
5813 dist = trace.fraction * r_editlights_cursordistance.value;
5814 push = r_editlights_cursorpushback.value;
5818 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5819 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5823 VectorClear( endpos );
5825 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5826 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5827 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5830 void R_Shadow_UpdateWorldLightSelection(void)
5832 if (r_editlights.integer)
5834 R_Shadow_SetCursorLocationForView();
5835 R_Shadow_SelectLightInView();
5838 R_Shadow_SelectLight(NULL);
5841 void R_Shadow_EditLights_Clear_f(void)
5843 R_Shadow_ClearWorldLights();
5846 void R_Shadow_EditLights_Reload_f(void)
5850 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5851 R_Shadow_ClearWorldLights();
5852 R_Shadow_LoadWorldLights();
5853 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5855 R_Shadow_LoadLightsFile();
5856 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5857 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5861 void R_Shadow_EditLights_Save_f(void)
5865 R_Shadow_SaveWorldLights();
5868 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5870 R_Shadow_ClearWorldLights();
5871 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5874 void R_Shadow_EditLights_ImportLightsFile_f(void)
5876 R_Shadow_ClearWorldLights();
5877 R_Shadow_LoadLightsFile();
5880 void R_Shadow_EditLights_Spawn_f(void)
5883 if (!r_editlights.integer)
5885 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5888 if (Cmd_Argc() != 1)
5890 Con_Print("r_editlights_spawn does not take parameters\n");
5893 color[0] = color[1] = color[2] = 1;
5894 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5897 void R_Shadow_EditLights_Edit_f(void)
5899 vec3_t origin, angles, color;
5900 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5901 int style, shadows, flags, normalmode, realtimemode;
5902 char cubemapname[MAX_INPUTLINE];
5903 if (!r_editlights.integer)
5905 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5908 if (!r_shadow_selectedlight)
5910 Con_Print("No selected light.\n");
5913 VectorCopy(r_shadow_selectedlight->origin, origin);
5914 VectorCopy(r_shadow_selectedlight->angles, angles);
5915 VectorCopy(r_shadow_selectedlight->color, color);
5916 radius = r_shadow_selectedlight->radius;
5917 style = r_shadow_selectedlight->style;
5918 if (r_shadow_selectedlight->cubemapname)
5919 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5922 shadows = r_shadow_selectedlight->shadow;
5923 corona = r_shadow_selectedlight->corona;
5924 coronasizescale = r_shadow_selectedlight->coronasizescale;
5925 ambientscale = r_shadow_selectedlight->ambientscale;
5926 diffusescale = r_shadow_selectedlight->diffusescale;
5927 specularscale = r_shadow_selectedlight->specularscale;
5928 flags = r_shadow_selectedlight->flags;
5929 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5930 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5931 if (!strcmp(Cmd_Argv(1), "origin"))
5933 if (Cmd_Argc() != 5)
5935 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5938 origin[0] = atof(Cmd_Argv(2));
5939 origin[1] = atof(Cmd_Argv(3));
5940 origin[2] = atof(Cmd_Argv(4));
5942 else if (!strcmp(Cmd_Argv(1), "originx"))
5944 if (Cmd_Argc() != 3)
5946 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5949 origin[0] = atof(Cmd_Argv(2));
5951 else if (!strcmp(Cmd_Argv(1), "originy"))
5953 if (Cmd_Argc() != 3)
5955 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5958 origin[1] = atof(Cmd_Argv(2));
5960 else if (!strcmp(Cmd_Argv(1), "originz"))
5962 if (Cmd_Argc() != 3)
5964 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5967 origin[2] = atof(Cmd_Argv(2));
5969 else if (!strcmp(Cmd_Argv(1), "move"))
5971 if (Cmd_Argc() != 5)
5973 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5976 origin[0] += atof(Cmd_Argv(2));
5977 origin[1] += atof(Cmd_Argv(3));
5978 origin[2] += atof(Cmd_Argv(4));
5980 else if (!strcmp(Cmd_Argv(1), "movex"))
5982 if (Cmd_Argc() != 3)
5984 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5987 origin[0] += atof(Cmd_Argv(2));
5989 else if (!strcmp(Cmd_Argv(1), "movey"))
5991 if (Cmd_Argc() != 3)
5993 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5996 origin[1] += atof(Cmd_Argv(2));
5998 else if (!strcmp(Cmd_Argv(1), "movez"))
6000 if (Cmd_Argc() != 3)
6002 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6005 origin[2] += atof(Cmd_Argv(2));
6007 else if (!strcmp(Cmd_Argv(1), "angles"))
6009 if (Cmd_Argc() != 5)
6011 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6014 angles[0] = atof(Cmd_Argv(2));
6015 angles[1] = atof(Cmd_Argv(3));
6016 angles[2] = atof(Cmd_Argv(4));
6018 else if (!strcmp(Cmd_Argv(1), "anglesx"))
6020 if (Cmd_Argc() != 3)
6022 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6025 angles[0] = atof(Cmd_Argv(2));
6027 else if (!strcmp(Cmd_Argv(1), "anglesy"))
6029 if (Cmd_Argc() != 3)
6031 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6034 angles[1] = atof(Cmd_Argv(2));
6036 else if (!strcmp(Cmd_Argv(1), "anglesz"))
6038 if (Cmd_Argc() != 3)
6040 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6043 angles[2] = atof(Cmd_Argv(2));
6045 else if (!strcmp(Cmd_Argv(1), "color"))
6047 if (Cmd_Argc() != 5)
6049 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
6052 color[0] = atof(Cmd_Argv(2));
6053 color[1] = atof(Cmd_Argv(3));
6054 color[2] = atof(Cmd_Argv(4));
6056 else if (!strcmp(Cmd_Argv(1), "radius"))
6058 if (Cmd_Argc() != 3)
6060 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6063 radius = atof(Cmd_Argv(2));
6065 else if (!strcmp(Cmd_Argv(1), "colorscale"))
6067 if (Cmd_Argc() == 3)
6069 double scale = atof(Cmd_Argv(2));
6076 if (Cmd_Argc() != 5)
6078 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
6081 color[0] *= atof(Cmd_Argv(2));
6082 color[1] *= atof(Cmd_Argv(3));
6083 color[2] *= atof(Cmd_Argv(4));
6086 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
6088 if (Cmd_Argc() != 3)
6090 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6093 radius *= atof(Cmd_Argv(2));
6095 else if (!strcmp(Cmd_Argv(1), "style"))
6097 if (Cmd_Argc() != 3)
6099 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6102 style = atoi(Cmd_Argv(2));
6104 else if (!strcmp(Cmd_Argv(1), "cubemap"))
6108 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6111 if (Cmd_Argc() == 3)
6112 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
6116 else if (!strcmp(Cmd_Argv(1), "shadows"))
6118 if (Cmd_Argc() != 3)
6120 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6123 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6125 else if (!strcmp(Cmd_Argv(1), "corona"))
6127 if (Cmd_Argc() != 3)
6129 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6132 corona = atof(Cmd_Argv(2));
6134 else if (!strcmp(Cmd_Argv(1), "coronasize"))
6136 if (Cmd_Argc() != 3)
6138 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6141 coronasizescale = atof(Cmd_Argv(2));
6143 else if (!strcmp(Cmd_Argv(1), "ambient"))
6145 if (Cmd_Argc() != 3)
6147 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6150 ambientscale = atof(Cmd_Argv(2));
6152 else if (!strcmp(Cmd_Argv(1), "diffuse"))
6154 if (Cmd_Argc() != 3)
6156 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6159 diffusescale = atof(Cmd_Argv(2));
6161 else if (!strcmp(Cmd_Argv(1), "specular"))
6163 if (Cmd_Argc() != 3)
6165 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6168 specularscale = atof(Cmd_Argv(2));
6170 else if (!strcmp(Cmd_Argv(1), "normalmode"))
6172 if (Cmd_Argc() != 3)
6174 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6177 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6179 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
6181 if (Cmd_Argc() != 3)
6183 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6186 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6190 Con_Print("usage: r_editlights_edit [property] [value]\n");
6191 Con_Print("Selected light's properties:\n");
6192 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6193 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6194 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6195 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
6196 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
6197 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
6198 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
6199 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
6200 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
6201 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
6202 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
6203 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
6204 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
6205 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
6208 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
6209 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6212 void R_Shadow_EditLights_EditAll_f(void)
6215 dlight_t *light, *oldselected;
6218 if (!r_editlights.integer)
6220 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
6224 oldselected = r_shadow_selectedlight;
6225 // EditLights doesn't seem to have a "remove" command or something so:
6226 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6227 for (lightindex = 0;lightindex < range;lightindex++)
6229 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6232 R_Shadow_SelectLight(light);
6233 R_Shadow_EditLights_Edit_f();
6235 // return to old selected (to not mess editing once selection is locked)
6236 R_Shadow_SelectLight(oldselected);
6239 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
6241 int lightnumber, lightcount;
6242 size_t lightindex, range;
6246 if (!r_editlights.integer)
6248 x = vid_conwidth.value - 240;
6250 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
6253 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6254 for (lightindex = 0;lightindex < range;lightindex++)
6256 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6259 if (light == r_shadow_selectedlight)
6260 lightnumber = lightindex;
6263 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;
6264 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;
6266 if (r_shadow_selectedlight == NULL)
6268 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;
6269 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;
6270 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;
6271 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;
6272 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;
6273 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;
6274 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;
6275 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;
6276 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;
6277 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;
6278 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;
6279 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;
6280 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;
6281 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;
6282 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;
6285 void R_Shadow_EditLights_ToggleShadow_f(void)
6287 if (!r_editlights.integer)
6289 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6292 if (!r_shadow_selectedlight)
6294 Con_Print("No selected light.\n");
6297 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);
6300 void R_Shadow_EditLights_ToggleCorona_f(void)
6302 if (!r_editlights.integer)
6304 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6307 if (!r_shadow_selectedlight)
6309 Con_Print("No selected light.\n");
6312 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);
6315 void R_Shadow_EditLights_Remove_f(void)
6317 if (!r_editlights.integer)
6319 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
6322 if (!r_shadow_selectedlight)
6324 Con_Print("No selected light.\n");
6327 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
6328 r_shadow_selectedlight = NULL;
6331 void R_Shadow_EditLights_Help_f(void)
6334 "Documentation on r_editlights system:\n"
6336 "r_editlights : enable/disable editing mode\n"
6337 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
6338 "r_editlights_cursorpushback : push back cursor this far from surface\n"
6339 "r_editlights_cursorpushoff : push cursor off surface this far\n"
6340 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
6341 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
6343 "r_editlights_help : this help\n"
6344 "r_editlights_clear : remove all lights\n"
6345 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
6346 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
6347 "r_editlights_save : save to .rtlights file\n"
6348 "r_editlights_spawn : create a light with default settings\n"
6349 "r_editlights_edit command : edit selected light - more documentation below\n"
6350 "r_editlights_remove : remove selected light\n"
6351 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
6352 "r_editlights_importlightentitiesfrommap : reload light entities\n"
6353 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
6355 "origin x y z : set light location\n"
6356 "originx x: set x component of light location\n"
6357 "originy y: set y component of light location\n"
6358 "originz z: set z component of light location\n"
6359 "move x y z : adjust light location\n"
6360 "movex x: adjust x component of light location\n"
6361 "movey y: adjust y component of light location\n"
6362 "movez z: adjust z component of light location\n"
6363 "angles x y z : set light angles\n"
6364 "anglesx x: set x component of light angles\n"
6365 "anglesy y: set y component of light angles\n"
6366 "anglesz z: set z component of light angles\n"
6367 "color r g b : set color of light (can be brighter than 1 1 1)\n"
6368 "radius radius : set radius (size) of light\n"
6369 "colorscale grey : multiply color of light (1 does nothing)\n"
6370 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
6371 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
6372 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
6373 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
6374 "cubemap basename : set filter cubemap of light (not yet supported)\n"
6375 "shadows 1/0 : turn on/off shadows\n"
6376 "corona n : set corona intensity\n"
6377 "coronasize n : set corona size (0-1)\n"
6378 "ambient n : set ambient intensity (0-1)\n"
6379 "diffuse n : set diffuse intensity (0-1)\n"
6380 "specular n : set specular intensity (0-1)\n"
6381 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6382 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6383 "<nothing> : print light properties to console\n"
6387 void R_Shadow_EditLights_CopyInfo_f(void)
6389 if (!r_editlights.integer)
6391 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
6394 if (!r_shadow_selectedlight)
6396 Con_Print("No selected light.\n");
6399 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6400 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6401 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6402 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6403 if (r_shadow_selectedlight->cubemapname)
6404 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6406 r_shadow_bufferlight.cubemapname[0] = 0;
6407 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6408 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6409 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6410 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6411 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6412 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6413 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6416 void R_Shadow_EditLights_PasteInfo_f(void)
6418 if (!r_editlights.integer)
6420 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6423 if (!r_shadow_selectedlight)
6425 Con_Print("No selected light.\n");
6428 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);
6431 void R_Shadow_EditLights_Lock_f(void)
6433 if (!r_editlights.integer)
6435 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6438 if (r_editlights_lockcursor)
6440 r_editlights_lockcursor = false;
6443 if (!r_shadow_selectedlight)
6445 Con_Print("No selected light to lock on.\n");
6448 r_editlights_lockcursor = true;
6451 void R_Shadow_EditLights_Init(void)
6453 Cvar_RegisterVariable(&r_editlights);
6454 Cvar_RegisterVariable(&r_editlights_cursordistance);
6455 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6456 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6457 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6458 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6459 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6460 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6461 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)");
6462 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6463 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6464 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6465 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)");
6466 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6467 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6468 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6469 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6470 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6471 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6472 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)");
6473 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6479 =============================================================================
6483 =============================================================================
6486 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
6488 int i, numlights, flag;
6491 float relativepoint[3];
6500 if (r_fullbright.integer)
6502 VectorSet(ambient, 1, 1, 1);
6503 VectorClear(diffuse);
6504 VectorClear(lightdir);
6508 if (flags & LP_LIGHTMAP)
6510 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6511 VectorClear(diffuse);
6512 VectorClear(lightdir);
6513 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6514 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
6518 memset(sample, 0, sizeof(sample));
6519 VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6521 if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6524 VectorClear(tempambient);
6526 VectorClear(relativepoint);
6527 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6528 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
6529 VectorScale(color, r_refdef.lightmapintensity, color);
6530 VectorAdd(sample, tempambient, sample);
6531 VectorMA(sample , 0.5f , color, sample );
6532 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6533 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6534 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6535 // calculate a weighted average light direction as well
6536 intensity = VectorLength(color);
6537 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6540 if (flags & LP_RTWORLD)
6542 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6543 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6544 for (i = 0; i < numlights; i++)
6546 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6549 light = &dlight->rtlight;
6550 if (!(light->flags & flag))
6553 lightradius2 = light->radius * light->radius;
6554 VectorSubtract(light->shadoworigin, p, relativepoint);
6555 dist2 = VectorLength2(relativepoint);
6556 if (dist2 >= lightradius2)
6558 dist = sqrt(dist2) / light->radius;
6559 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6560 if (intensity <= 0.0f)
6562 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1)
6564 // scale down intensity to add to both ambient and diffuse
6565 //intensity *= 0.5f;
6566 VectorNormalize(relativepoint);
6567 VectorScale(light->currentcolor, intensity, color);
6568 VectorMA(sample , 0.5f , color, sample );
6569 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6570 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6571 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6572 // calculate a weighted average light direction as well
6573 intensity *= VectorLength(color);
6574 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6578 if (flags & LP_DYNLIGHT)
6581 for (i = 0;i < r_refdef.scene.numlights;i++)
6583 light = r_refdef.scene.lights[i];
6585 lightradius2 = light->radius * light->radius;
6586 VectorSubtract(light->shadoworigin, p, relativepoint);
6587 dist2 = VectorLength2(relativepoint);
6588 if (dist2 >= lightradius2)
6590 dist = sqrt(dist2) / light->radius;
6591 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6592 if (intensity <= 0.0f)
6594 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1)
6596 // scale down intensity to add to both ambient and diffuse
6597 //intensity *= 0.5f;
6598 VectorNormalize(relativepoint);
6599 VectorScale(light->currentcolor, intensity, color);
6600 VectorMA(sample , 0.5f , color, sample );
6601 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6602 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6603 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6604 // calculate a weighted average light direction as well
6605 intensity *= VectorLength(color);
6606 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6610 // calculate the direction we'll use to reduce the sample to a directional light source
6611 VectorCopy(sample + 12, dir);
6612 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
6613 VectorNormalize(dir);
6614 // extract the diffuse color along the chosen direction and scale it
6615 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
6616 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
6617 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
6618 // subtract some of diffuse from ambient
6619 VectorMA(sample, -0.333f, diffuse, ambient);
6620 // store the normalized lightdir
6621 VectorCopy(dir, lightdir);